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-02 03:25:23 +00:00
|
|
|
#define SUBD_SPLIT 1
|
2009-02-08 14:25:04 +00:00
|
|
|
|
|
|
|
|
/*I don't think new faces are flagged, currently, but
|
|
|
|
|
better safe than sorry.*/
|
|
|
|
|
#define FACE_NEW 2
|
|
|
|
|
#define FACE_CUSTOMFILL 4
|
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-02-02 03:25:23 +00:00
|
|
|
/* calculates offset for co, based on fractal, sphere or smooth settings */
|
2009-02-03 06:22:30 +00:00
|
|
|
static void alter_co(float *co, BMEdge *edge, float rad, int flag, float perc,
|
|
|
|
|
BMVert *vsta, BMVert *vend)
|
2009-02-02 03:25:23 +00:00
|
|
|
{
|
|
|
|
|
float vec1[3], fac;
|
|
|
|
|
|
2009-02-03 06:22:30 +00:00
|
|
|
if(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];
|
|
|
|
|
|
|
|
|
|
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 */
|
2009-02-03 06:22:30 +00:00
|
|
|
fac= 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 */
|
|
|
|
|
static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, float rad,
|
2009-02-03 06:22:30 +00:00
|
|
|
int flag, float percent, BMEdge **out,
|
|
|
|
|
BMVert *vsta, BMVert *vend)
|
2009-02-02 03:25:23 +00:00
|
|
|
{
|
|
|
|
|
BMVert *ev;
|
|
|
|
|
// float co[3];
|
|
|
|
|
|
|
|
|
|
ev = BM_Split_Edge(bm, edge->v1, edge, out, percent, 1);
|
2009-02-08 11:53:14 +00:00
|
|
|
if (flag & SELTYPE_INNER) BM_Select_Vert(bm, ev, 1);
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/* offset for smooth or sphere or fractal */
|
2009-02-03 06:22:30 +00:00
|
|
|
alter_co(ev->co, edge, rad, flag, percent, 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-02-02 03:25:23 +00:00
|
|
|
static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge,
|
|
|
|
|
int curpoint, int totpoint, float rad,
|
2009-02-03 06:22:30 +00:00
|
|
|
int flag, BMEdge **newe,
|
|
|
|
|
BMVert *vsta, BMVert *vend)
|
2009-02-02 03:25:23 +00:00
|
|
|
{
|
|
|
|
|
BMVert *ev;
|
|
|
|
|
float percent;
|
|
|
|
|
|
2009-02-03 06:22:30 +00:00
|
|
|
if (flag & (B_PERCENTSUBD) && totpoint == 1)
|
2009-02-02 03:25:23 +00:00
|
|
|
/*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);
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*{
|
|
|
|
|
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);
|
2009-01-07 15:17:58 +00:00
|
|
|
*/
|
2009-02-03 06:22:30 +00:00
|
|
|
ev= bm_subdivide_edge_addvert(bm, edge, rad, flag, percent,
|
|
|
|
|
newe, vsta, vend);
|
2009-02-08 11:53:14 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/* VECCOPY(ev->co, co2);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
return ev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, float rad,
|
2009-02-03 06:22:30 +00:00
|
|
|
int flag, int numcuts,
|
|
|
|
|
BMVert *vsta, BMVert *vend) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMEdge *eed = edge, *newe;
|
|
|
|
|
BMVert *v;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for(i=0;i<numcuts;i++) {
|
2009-02-03 06:22:30 +00:00
|
|
|
v = subdivideedgenum(bm, eed, i, numcuts, rad,
|
|
|
|
|
flag, &newe, vsta, vend);
|
2009-02-02 03:25:23 +00:00
|
|
|
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 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-02 03:25:23 +00:00
|
|
|
static void q_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
|
2009-02-03 06:22:30 +00:00
|
|
|
int flag, float rad) {
|
2009-02-02 03:25:23 +00:00
|
|
|
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;
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add],
|
|
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
add = 2;
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add],
|
|
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
if (i == numcuts/2) {
|
|
|
|
|
add -= 1;
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[i],
|
|
|
|
|
vlist[numcuts+add],
|
|
|
|
|
&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-02 03:25:23 +00:00
|
|
|
static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **vlist,
|
2009-02-03 06:22:30 +00:00
|
|
|
int numcuts, int flag, float rad) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[i],vlist[(numcuts-i-1)+numcuts+2],
|
|
|
|
|
&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-02 03:25:23 +00:00
|
|
|
static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
|
2009-02-03 06:22:30 +00:00
|
|
|
int numcuts, int flag, float rad) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+(numcuts-i)],
|
|
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
BM_Connect_Verts(bm, vlist[numcuts*2+3], vlist[numcuts*2+1], &nf);
|
|
|
|
|
}
|
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-02 03:25:23 +00:00
|
|
|
static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
|
2009-02-03 06:22:30 +00:00
|
|
|
int numcuts, int flag, float rad) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
|
|
|
|
int i, add=0;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
if (i == numcuts/2) {
|
|
|
|
|
if (numcuts % 2 != 0) {
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[numcuts-i-1+add],
|
|
|
|
|
vlist[i+numcuts+1], &nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
add = numcuts*2+2;
|
|
|
|
|
}
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[numcuts-i-1+add],
|
|
|
|
|
vlist[i+numcuts+1], &nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts/2+1; i++) {
|
2009-02-08 11:53:14 +00:00
|
|
|
BM_Connect_Verts(bm, vlist[i],vlist[(numcuts-i)+numcuts*2+1],
|
|
|
|
|
&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
|
|
|
|
|
*/
|
|
|
|
|
static void q_4edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
|
2009-02-03 06:22:30 +00:00
|
|
|
int flag, float rad) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
2009-02-03 06:22:30 +00:00
|
|
|
BMVert *v, *v1, *v2;
|
2009-02-02 03:25:23 +00:00
|
|
|
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)];
|
|
|
|
|
}
|
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++) {
|
|
|
|
|
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);
|
2009-02-08 11:53:14 +00:00
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, e, 1);
|
|
|
|
|
BM_Select_Face(bm, nf, 1);
|
|
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-02-03 06:22:30 +00:00
|
|
|
v1 = lines[(i+1)*s] = vlist[a];
|
|
|
|
|
v2 = lines[(i+1)*s + s-1] = vlist[b];
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
for (a=0; a<numcuts; a++) {
|
2009-02-03 06:22:30 +00:00
|
|
|
v = subdivideedgenum(bm, e, a, numcuts, rad, flag, &ne,
|
|
|
|
|
v1, v2);
|
2009-02-08 11:53:14 +00:00
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, ne, 1);
|
|
|
|
|
}
|
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-02-08 11:53:14 +00:00
|
|
|
e = BM_Connect_Verts(bm, lines[a], lines[b], &nf);
|
|
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, e, 1);
|
|
|
|
|
BM_Select_Face(bm, nf, 1);
|
|
|
|
|
}
|
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
|
|
|
|
|
*/
|
|
|
|
|
static void t_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
|
|
|
|
|
int numcuts, int flag, float rad) {
|
|
|
|
|
BMFace *nf;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+1], &nf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subdpattern t_1edge = {
|
|
|
|
|
{1, 0, 0},
|
|
|
|
|
t_1edge_split,
|
|
|
|
|
3,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* v5
|
|
|
|
|
/ \
|
|
|
|
|
/ \ v4 s
|
|
|
|
|
/ \
|
|
|
|
|
/ \ v3 s
|
|
|
|
|
/ \
|
|
|
|
|
v6--v0--v1--v2
|
|
|
|
|
s s
|
|
|
|
|
*/
|
|
|
|
|
static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
|
|
|
|
|
int numcuts, int flag, float rad) {
|
|
|
|
|
BMFace *nf;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+numcuts-i], &nf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
static void t_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
|
|
|
|
|
int numcuts, int flag, float rad) {
|
|
|
|
|
BMFace *nf;
|
|
|
|
|
BMEdge *e, *ne;
|
|
|
|
|
BMVert ***lines, *v;
|
|
|
|
|
void *stackarr[1];
|
2009-02-08 11:53:14 +00:00
|
|
|
int i, j, a, b;
|
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 08:52:25 +00:00
|
|
|
lines[0][0] = vlist[numcuts*2+1];
|
|
|
|
|
|
|
|
|
|
lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2),
|
|
|
|
|
"triangle vert table 2");
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
lines[1+numcuts][1+i] = vlist[i];
|
|
|
|
|
}
|
|
|
|
|
lines[1+numcuts][0] = vlist[numcuts*3+2];
|
|
|
|
|
lines[1+numcuts][1+numcuts] = vlist[numcuts];
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
e = BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
|
2009-02-08 11:53:14 +00:00
|
|
|
|
|
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, e, 1);
|
|
|
|
|
BM_Select_Face(bm, nf, 1);
|
|
|
|
|
}
|
2009-02-08 08:52:25 +00:00
|
|
|
|
|
|
|
|
lines[i+1][0] = vlist[a];
|
|
|
|
|
lines[i+1][1+i] = vlist[b];
|
|
|
|
|
|
|
|
|
|
for (j=0; j<i; j++) {
|
|
|
|
|
v = subdivideedgenum(bm, e, j, i, rad, flag, &ne,
|
|
|
|
|
vlist[a], vlist[b]);
|
|
|
|
|
lines[i+1][j+1] = v;
|
2009-02-08 11:53:14 +00:00
|
|
|
|
|
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, ne, 1);
|
|
|
|
|
}
|
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-02-08 11:53:14 +00:00
|
|
|
e= BM_Connect_Verts(bm, lines[i][j], lines[i+1][j+1],
|
|
|
|
|
&nf);
|
|
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, e, 1);
|
|
|
|
|
BM_Select_Face(bm, nf, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e= BM_Connect_Verts(bm,lines[i][j+1],lines[i+1][j+1],
|
|
|
|
|
&nf);
|
|
|
|
|
if (flag & SELTYPE_INNER) {
|
|
|
|
|
BM_Select_Edge(bm, e, 1);
|
|
|
|
|
BM_Select_Face(bm, nf, 1);
|
|
|
|
|
}
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-08 11:53:14 +00:00
|
|
|
for (i=1; i<numcuts+2; i++) {
|
2009-02-08 08:52:25 +00:00
|
|
|
MEM_freeN(lines[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-08 14:25:04 +00:00
|
|
|
V_DECLARE(facedata);
|
|
|
|
|
V_DECLARE(verts);
|
2009-02-08 11:53:14 +00:00
|
|
|
V_DECLARE(edges);
|
2009-02-08 14:25:04 +00:00
|
|
|
BMOpSlot *einput, *finput, *pinput;
|
|
|
|
|
BMEdge *edge, **edges = NULL;
|
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-02 03:25:23 +00:00
|
|
|
BMIter fiter, liter;
|
2009-02-08 14:25:04 +00:00
|
|
|
GHash *customfill_hash;
|
2009-01-07 15:17:58 +00:00
|
|
|
subdpattern *pat;
|
2009-02-02 03:25:23 +00:00
|
|
|
subd_facedata *facedata = NULL;
|
2009-02-08 14:25:04 +00:00
|
|
|
float rad;
|
|
|
|
|
int i, j, matched, a, b, numcuts, flag, selaction, fillindex;
|
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-02-02 03:25:23 +00:00
|
|
|
selaction = BMO_GetSlot(op, BMOP_ESUBDIVIDE_SELACTION)->data.i;
|
2009-02-08 11:53:14 +00:00
|
|
|
if (selaction == SUBDIV_SELECT_INNER) flag |= SELTYPE_INNER;
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
/*first go through and split edges*/
|
2009-01-22 13:59:30 +00:00
|
|
|
for (i=0; i<einput->len; i++) {
|
|
|
|
|
edge = ((BMEdge**)einput->data.p)[i];
|
2009-02-02 03:25:23 +00:00
|
|
|
BMO_SetFlag(bmesh, edge, SUBD_SPLIT);
|
2009-01-07 15:17:58 +00:00
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-02-08 14:25:04 +00:00
|
|
|
customfill_hash = BLI_ghash_new(BLI_ghashutil_ptrhash,
|
|
|
|
|
BLI_ghashutil_ptrcmp);
|
|
|
|
|
|
|
|
|
|
/*process custom fill patterns*/
|
|
|
|
|
finput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_CUSTOMFILL_FACES);
|
|
|
|
|
pinput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_CUSTOMFILL_PATTERNS);
|
|
|
|
|
for (i=0; i<finput->len; i++) {
|
|
|
|
|
face = ((BMFace**)finput->data.p)[i];
|
|
|
|
|
BMO_SetFlag(bmesh, face, FACE_CUSTOMFILL);
|
|
|
|
|
BLI_ghash_insert(customfill_hash, face,
|
|
|
|
|
((void**)pinput->data.p)[i]);
|
|
|
|
|
}
|
|
|
|
|
|
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)) {
|
|
|
|
|
pat = BLI_ghash_lookup(customfill_hash, face);
|
|
|
|
|
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];
|
|
|
|
|
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-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-03 06:22:30 +00:00
|
|
|
bm_subdivide_multicut(bmesh, edge, rad, flag, numcuts,
|
|
|
|
|
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
|
|
|
|
|
|
|
|
pat->connectexec(bmesh, face, verts, numcuts, flag, rad);
|
|
|
|
|
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-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;
|
|
|
|
|
|
|
|
|
|
BMO_Init_Op(&op, BMOP_ESUBDIVIDE);
|
2009-02-03 06:22:30 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
BMO_Set_Int(&op, BMOP_ESUBDIVIDE_NUMCUTS, numcuts);
|
2009-02-03 06:22:30 +00:00
|
|
|
BMO_Set_Int(&op, BMOP_ESUBDIVIDE_FLAG, flag);
|
2009-02-02 03:25:23 +00:00
|
|
|
BMO_Set_Float(&op, BMOP_ESUBDIVIDE_RADIUS, rad);
|
|
|
|
|
BMO_Set_Int(&op, BMOP_ESUBDIVIDE_SELACTION, seltype);
|
2009-02-03 06:22:30 +00:00
|
|
|
BMO_HeaderFlag_To_Slot(bm, &op, BMOP_ESUBDIVIDE_EDGES, selflag, BM_EDGE);
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
BMO_Exec_Op(bm, &op);
|
|
|
|
|
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);
|
|
|
|
|
}
|