Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2013-01-21 05:52:23 +0400
committerHoward Trickey <howard.trickey@gmail.com>2013-01-21 05:52:23 +0400
commitadd25e43adae7204d27685eafefde343096d5698 (patch)
treef9175dd682123514d4cd41d02e27e418f8d8bc65 /source/blender/bmesh/tools
parent8e934014d7a43acb62f1a2625a6979babfdcabc5 (diff)
Bevel vertex only (shortcut: control-shift-B) initial commit.
Diffstat (limited to 'source/blender/bmesh/tools')
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c593
1 files changed, 388 insertions, 205 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index a593e40d850..121f1f2fd67 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -41,9 +41,6 @@
-/* experemental - Campbell */
-// #define USE_ALTERNATE_ADJ
-
#define BEVEL_EPSILON 1e-6
/* for testing */
@@ -94,7 +91,7 @@ typedef struct VMesh {
M_NONE, /* no polygon mesh needed */
M_POLY, /* a simple polygon */
M_ADJ, /* "adjacent edges" mesh pattern */
-// M_CROSS, /* "cross edges" mesh pattern */
+ M_ADJ_SUBDIV, /* like M_ADJ, but using subdivision */
M_TRI_FAN, /* a simple polygon - fan filled */
M_QUAD_STRIP, /* a simple polygon - cut into paralelle strips */
} mesh_kind;
@@ -124,7 +121,7 @@ typedef struct BevelParams {
// #pragma GCC diagnostic ignored "-Wpadded"
-//#include "bevdebug.c"
+// #include "bevdebug.c"
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
@@ -501,79 +498,6 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f)
return lb->next == la ? 1 : -1;
}
-#ifdef USE_ALTERNATE_ADJ
-
-static void vmesh_cent(VMesh *vm, float r_cent[3])
-{
- BoundVert *v;
- zero_v3(r_cent);
-
- v = vm->boundstart;
- do {
- add_v3_v3(r_cent, v->nv.co);
- } while ((v = v->next) != vm->boundstart);
- mul_v3_fl(r_cent, 1.0f / (float)vm->count);
-}
-
-/**
- *
- * This example shows a tri fan of quads,
- * but could be an NGon fan of quads too.
- * <pre>
- * The whole triangle X
- * represents the / \
- * new bevel face. / \
- * / \
- * Split into / \
- * a quad fan. / \
- * / \
- * / \
- * / \
- * co_prev +-. .-+
- * / `-._ _.-' \
- * / co_cent`-+-' \
- * / | \
- * Quad of / | \
- * interest -- / ---> X | \
- * / | \
- * / | \
- * / co_next| \
- * co_orig +-----------------+-----------------+
- *
- * For each quad, calcualte UV's based on the following:
- * U = k / (vm->seg * 2)
- * V = ring / (vm->seg * 2)
- * quad = (co_orig, co_prev, co_cent, co_next)
- * ... note that co_cent is the same for all quads in the fan.
- * </pre>
- *
- */
-
-static void get_point_uv(float uv[2],
- /* all these args are int's originally
- * but pass as floats to the function */
- const float seg, const float ring, const float k)
-{
- uv[0] = (ring / seg) * 2.0f;
- uv[1] = (k / seg) * 2.0f;
-}
-
-/* TODO: make this a lot smarter!,
- * this is the main reason USE_ALTERNATE_ADJ isn't so good right now :S */
-static float get_point_uv_factor(const float uv[2])
-{
- return sinf(1.0f - max_ff(uv[0], uv[1]) / 2.0f);
-}
-
-static void get_point_on_round_edge(const float uv[2],
- float quad[4][3],
- float r_co[3])
-{
- interp_bilinear_quad_v3(quad, uv[0], uv[1], r_co);
-}
-
-#else /* USE_ALTERNATE_ADJ */
-
/* Fill matrix r_mat so that a point in the sheared parallelogram with corners
* va, vmid, vb (and the 4th that is implied by it being a parallelogram)
* is transformed to the unit square by multiplication with r_mat.
@@ -694,8 +618,6 @@ static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[
}
}
-#endif /* !USE_ALTERNATE_ADJ */
-
/* Make a circular list of BoundVerts for bv, each of which has the coordinates
* of a vertex on the the boundary of the beveled vertex bv->v.
* Also decide on the mesh pattern that will be used inside the boundary.
@@ -811,7 +733,10 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
} while ((e = e->next) != efirst);
BLI_assert(vm->count >= 2);
- if (vm->count == 2 && bv->edgecount == 3) {
+ if (bp->vertex_only) {
+ vm->mesh_kind = bp->seg > 1 ? M_ADJ_SUBDIV : M_POLY;
+ }
+ else if (vm->count == 2 && bv->edgecount == 3) {
vm->mesh_kind = M_NONE;
}
else if (bv->selcount == 2) {
@@ -846,19 +771,6 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
float co[3], coa[3], cob[3], midco[3];
float va_pipe[3], vb_pipe[3];
-#ifdef USE_ALTERNATE_ADJ
- /* ordered as follows (orig, prev, center, next)*/
- float quad_plane[4][3];
- float quad_orig[4][3];
-#endif
-
-
-#ifdef USE_ALTERNATE_ADJ
- /* the rest are initialized inline, this remains the same for all */
- vmesh_cent(vm, quad_plane[2]);
- copy_v3_v3(quad_orig[2], bv->v->co);
-#endif
-
n = vm->count;
ns = vm->seg;
ns2 = ns / 2;
@@ -918,37 +830,6 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
copy_v3_v3(nv->co, cob);
nv->v = nvnext->v;
-#ifdef USE_ALTERNATE_ADJ
- /* plane */
- copy_v3_v3(quad_plane[0], v->nv.co);
- mid_v3_v3v3(quad_plane[1], v->nv.co, v->prev->nv.co);
- /* quad[2] is set */
- mid_v3_v3v3(quad_plane[3], v->nv.co, v->next->nv.co);
-
- /* orig */
- copy_v3_v3(quad_orig[0], v->nv.co); /* only shared location between 2 quads */
- project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig[1]);
- project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig[3]);
-
- //bl_debug_draw_quad_add(UNPACK4(quad_plane));
- //bl_debug_draw_quad_add(UNPACK4(quad_orig));
-#endif
-
-#ifdef USE_ALTERNATE_ADJ
- for (k = 1; k < ns; k++) {
- float uv[2];
- float fac;
- float co_plane[3];
- float co_orig[3];
-
- get_point_uv(uv, v->ebev->seg, ring, k);
- get_point_on_round_edge(uv, quad_plane, co_plane);
- get_point_on_round_edge(uv, quad_orig, co_orig);
- fac = get_point_uv_factor(uv);
- interp_v3_v3v3(co, co_plane, co_orig, fac);
- copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co);
- }
-#else
/* TODO: better calculation of new midarc point? */
project_to_edge(v->ebev->e, coa, cob, midco);
@@ -962,7 +843,6 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
copy_v3_v3(va_pipe, mesh_vert(vm, i, 0, 0)->co);
copy_v3_v3(vb_pipe, mesh_vert(vm, i, 0, ns)->co);
}
-#endif
}
} while ((v = v->next) != vm->boundstart);
}
@@ -990,9 +870,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
-#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
-#endif
BLI_assert(nv->v == NULL && nvprev->v == NULL);
create_mesh_bmvert(bm, vm, i, ring, k, bv->v);
copy_mesh_vert(vm, vprev->index, k, ns - ring, i, ring, k);
@@ -1041,9 +919,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
mid_v3_v3v3v3(co, nvprev->co, nv->co, nvnext->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
-#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
-#endif
create_mesh_bmvert(bm, vm, i, k, ns2, bv->v);
copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2);
copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2);
@@ -1053,9 +929,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
mid_v3_v3v3(co, nvprev->co, nv->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
-#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
-#endif
create_mesh_bmvert(bm, vm, i, k, ns2, bv->v);
copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2);
@@ -1065,9 +939,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
mid_v3_v3v3(co, nv->co, nvnext->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
-#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
-#endif
create_mesh_bmvert(bm, vm, i, k, ns2, bv->v);
copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2);
@@ -1220,6 +1092,385 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
}
+static VMesh* new_adj_subdiv_vmesh(MemArena *mem_arena, int count, int seg)
+{
+ VMesh *vm;
+
+ vm = (VMesh *)BLI_memarena_alloc(mem_arena, sizeof(VMesh));
+ vm->count = count;
+ vm->seg = seg;
+ vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, count * (1 + seg/2) * (1 + seg) * sizeof(NewVert));
+ vm->mesh_kind = M_ADJ_SUBDIV;
+ return vm;
+}
+
+/* VMesh verts for vertex i have data for (i, 0 <= j <= ns2, 0 <= k <= ns), where ns2 = floor(nseg / 2).
+ * But these overlap data from previous and next i: there are some forced equivalences.
+ * Let's call these indices the canonical ones: we will just calculate data for these
+ * 0 <= j <= ns2, 0 <= k < ns2 (for odd ns2)
+ * 0 <= j < ns2, 0 <= k <= ns2 (for even ns2)
+ * also (j=ns2, k=ns2) at i=0 (for even ns2)
+ * This function returns the canonical one for any i, j, k in [0,n],[0,ns],[0,ns] */
+static NewVert* mesh_vert_canon(VMesh *vm, int i, int j, int k)
+{
+ int n, ns, ns2, odd;
+ NewVert *ans;
+
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+ BLI_assert(0 <= i && i <= n && 0 <= j && j <= ns && 0 <= k && k <= ns);
+
+ if (!odd && j == ns2 && k == ns2)
+ ans = mesh_vert(vm, 0, j, k);
+ else if (j <= ns2 - 1 + odd && k <= ns2)
+ ans = mesh_vert(vm, i, j, k);
+ else if (k <= ns2)
+ ans = mesh_vert(vm, (i + n - 1) % n, k, ns - j);
+ else
+ ans = mesh_vert(vm, (i + 1) % n, ns - k, j);
+ return ans;
+}
+
+static int is_canon(VMesh *vm, int i, int j, int k)
+{
+ int ns2 = vm->seg / 2;
+ if (vm->seg % 2 == 1)
+ return (j <= ns2 && k <= ns2);
+ else
+ return ((j < ns2 && k <= ns2) || (j == ns2 && k == ns2 && i == 0));
+}
+
+/* Copy the vertex data to all of vm verts from canonical ones */
+static void vmesh_copy_equiv_verts(VMesh *vm)
+{
+ int n, ns, ns2, i, j, k;
+ NewVert *v0, *v1;
+
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+ for (i = 0; i < n; i++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= ns; k++) {
+ if (is_canon(vm, i, j, k))
+ continue;
+ v1 = mesh_vert(vm, i, j, k);
+ v0 = mesh_vert_canon(vm, i, j, k);
+ copy_v3_v3(v1->co, v0->co);
+ v1->v = v0->v;
+ }
+ }
+ }
+}
+
+/* Calculate and return in r_cent the centroid of the center poly */
+static void vmesh_center(VMesh *vm, float r_cent[3])
+{
+ int n, ns2, i;
+
+ n = vm->count;
+ ns2 = vm->seg / 2;
+ if (vm->seg % 2) {
+ zero_v3(r_cent);
+ for (i = 0; i < n; i++) {
+ add_v3_v3(r_cent, mesh_vert(vm, i, ns2, ns2)->co);
+ }
+ mul_v3_fl(r_cent, 1.0f / (float) n);
+ }
+ else {
+ copy_v3_v3(r_cent, mesh_vert(vm, 0, ns2, ns2)->co);
+ }
+}
+
+/* Do one step of quadratic subdivision (Doo-Sabin), with special rules at boundaries.
+ * For now, this is written assuming vm0->nseg is odd.
+ * See Hwang-Chuang 2003 paper: "N-sided hole filling and vertex blending using subdivision surfaces" */
+static VMesh* quadratic_subdiv(MemArena *mem_arena, VMesh *vm0)
+{
+ int n, ns0, ns20, ns1, ns21, i, j, k, j1, k1;
+ VMesh *vm1;
+ float co[3], co1[3], co2[3], co3[3], co4[3];
+ float co11[3], co21[3], co31[3], co41[3];
+ float denom;
+ const float wcorner[4] = {0.25f, 0.25f, 0.25f, 0.25f};
+ const float wboundary[4] = {0.375f, 0.375f, 0.125f, 0.125f}; /* {3, 3, 1, 1}/8 */
+ const float winterior[4] = {0.5625f, 0.1875f, 0.1875f, 0.0625f}; /* {9, 3, 3, 1}/16 */
+
+ n = vm0->count;
+ ns0 = vm0->seg;
+ ns20 = ns0 / 2;
+ BLI_assert(ns0 % 2 == 1);
+
+ ns1 = 2 * ns0 - 1;
+ ns21 = ns1 / 2;
+ vm1 = new_adj_subdiv_vmesh(mem_arena, n, ns1);
+
+ for (i = 0; i < n; i ++) {
+ /* For handle vm0 polys with lower left corner at (i,j,k) for
+ * j in [0, ns20], k in [0, ns20]; then the center ngon.
+ * but only fill in data for canonical verts of v1. */
+ for (j = 0; j <= ns20; j++) {
+ for (k = 0; k <= ns20; k++) {
+ if (j == ns20 && k == ns20)
+ continue; /* center ngon is special */
+ copy_v3_v3(co1, mesh_vert_canon(vm0, i, j, k)->co);
+ copy_v3_v3(co2, mesh_vert_canon(vm0, i, j, k + 1)->co);
+ copy_v3_v3(co3, mesh_vert_canon(vm0, i, j + 1, k + 1)->co);
+ copy_v3_v3(co4, mesh_vert_canon(vm0, i, j + 1, k)->co);
+ if (j == 0 && k == 0) {
+ /* corner */
+ copy_v3_v3(co11, co1);
+ interp_v3_v3v3(co21, co1, co2, 0.5f);
+ interp_v3_v3v3v3v3(co31, co1, co2, co3, co4, wcorner);
+ interp_v3_v3v3(co41, co1, co4, 0.5f);
+ }
+ else if (j == 0) {
+ /* ring 0 boundary */
+ interp_v3_v3v3(co11, co1, co2, 0.25f);
+ interp_v3_v3v3(co21, co1, co2, 0.75f);
+ interp_v3_v3v3v3v3(co31, co2, co3, co1, co4, wboundary);
+ interp_v3_v3v3v3v3(co41, co1, co4, co2, co3, wboundary);
+ }
+ else if (k == 0) {
+ /* ring-starts boundary */
+ interp_v3_v3v3(co11, co1, co4, 0.25f);
+ interp_v3_v3v3v3v3(co21, co1, co2, co3, co4, wboundary);
+ interp_v3_v3v3v3v3(co31, co3, co4, co1, co2, wboundary);
+ interp_v3_v3v3(co41, co1, co4, 0.75f);
+ }
+ else {
+ /* interior */
+ interp_v3_v3v3v3v3(co11, co1, co2, co4, co3, winterior);
+ interp_v3_v3v3v3v3(co21, co2, co1, co3, co4, winterior);
+ interp_v3_v3v3v3v3(co31, co3, co2, co4, co1, winterior);
+ interp_v3_v3v3v3v3(co41, co4, co1, co3, co2, winterior);
+ }
+ j1 = 2 * j;
+ k1 = 2 * k;
+ if (is_canon(vm1, i, j1, k1))
+ copy_v3_v3(mesh_vert(vm1, i, j1, k1)->co, co11);
+ if (is_canon(vm1, i, j1, k1 + 1))
+ copy_v3_v3(mesh_vert(vm1, i, j1, k1 + 1)->co, co21);
+ if (is_canon(vm1, i, j1 + 1, k1 + 1))
+ copy_v3_v3(mesh_vert(vm1, i, j1 + 1, k1 + 1)->co, co31);
+ if (is_canon(vm1, i, j1 + 1, k1))
+ copy_v3_v3(mesh_vert(vm1, i, j1 + 1, k1)->co, co41);
+ }
+ }
+
+ /* center ngon */
+ denom = 8.0f * (float) n;
+ zero_v3(co);
+ for (j = 0; j < n; j++) {
+ copy_v3_v3(co1, mesh_vert(vm0, j, ns20, ns20)->co);
+ if (i == j)
+ madd_v3_v3fl(co, co1, (4.0f * (float) n + 2.0f) / denom);
+ else if ((i + 1) % n == j || (i + n - 1) % n == j)
+ madd_v3_v3fl(co, co1, ((float) n + 2.0f) / denom);
+ else
+ madd_v3_v3fl(co, co1, 2.0f / denom);
+ }
+ copy_v3_v3(mesh_vert(vm1, i, 2 * ns20, 2 * ns20)->co, co);
+ }
+
+ vmesh_copy_equiv_verts(vm1);
+ return vm1;
+}
+
+/* Fill frac with fractions of way along ring 0 for vertex i, for use with interp_range function */
+static void fill_vmesh_fracs(VMesh *vm, float *frac, int i)
+{
+ int k, ns;
+ float total = 0.0f;
+
+ ns = vm->seg;
+ frac[0] = 0.0f;
+ for (k = 0; k < ns; k++) {
+ total += len_v3v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm, i, 0, k + 1)->co);
+ frac[k + 1] = total;
+ }
+ if (total > BEVEL_EPSILON) {
+ for (k = 1; k <= ns; k++)
+ frac[k] /= total;
+ }
+}
+
+/* Return i such that frac[i] <= f <= frac[i + 1], where frac[n] == 1.0
+ * and put fraction of rest of way between frac[i] and frac[i + 1] into r_rest */
+static int interp_range(const float *frac, int n, const float f, float *r_rest)
+{
+ int i;
+ float rest;
+
+ /* could binary search in frac, but expect n to be reasonably small */
+ for (i = 0; i < n; i++) {
+ if (f <= frac[i + 1]) {
+ rest = f - frac[i];
+ if (rest == 0)
+ *r_rest = 0.0f;
+ else
+ *r_rest = rest / (frac[i + 1] - frac[i]);
+ return i;
+ }
+ }
+ *r_rest = 0.0f;
+ return n;
+}
+
+/* Interpolate given vmesh to make one with target nseg and evenly spaced border vertices */
+static VMesh* interp_vmesh(MemArena *mem_arena, VMesh *vm0, int nseg)
+{
+ int n, ns0, nseg2, odd, i, j, k, j0, k0;
+ float *prev_frac, *frac, f, restj, restk;
+ float quad[4][3], co[3], center[3];
+ VMesh *vm1;
+
+ n = vm0->count;
+ ns0 = vm0->seg;
+ nseg2 = nseg / 2;
+ odd = nseg % 2;
+ vm1 = new_adj_subdiv_vmesh(mem_arena, n, nseg);
+ prev_frac = (float *)BLI_memarena_alloc(mem_arena, (ns0 + 1 ) *sizeof(float));
+ frac = (float *)BLI_memarena_alloc(mem_arena, (ns0 + 1 ) *sizeof(float));
+
+ fill_vmesh_fracs(vm0, prev_frac, n - 1);
+ fill_vmesh_fracs(vm0, frac, 0);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j <= nseg2 -1 + odd; j++) {
+ for (k = 0; k <= nseg2; k++) {
+ f = (float) k / (float) nseg;
+ k0 = interp_range(frac, ns0, f, &restk);
+ f = 1.0f - (float) j / (float) nseg;
+ j0 = interp_range(prev_frac, ns0, f, &restj);
+ if (restj < BEVEL_EPSILON) {
+ j0 = ns0 - j0;
+ restj = 0.0f;
+ }
+ else {
+ j0 = ns0 - j0 - 1;
+ restj = 1.0f - restj;
+ }
+ /* Use bilinear interpolation within the source quad; could be smarter here */
+ if (restj < BEVEL_EPSILON && restk < BEVEL_EPSILON) {
+ copy_v3_v3(co, mesh_vert_canon(vm0, i, j0, k0)->co);
+ }
+ else {
+ copy_v3_v3(quad[0], mesh_vert_canon(vm0, i, j0, k0)->co);
+ copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + 1)->co);
+ copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + 1, k0 + 1)->co);
+ copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + 1, k0)->co);
+ interp_bilinear_quad_v3(quad, restk, restj, co);
+ }
+ copy_v3_v3(mesh_vert(vm1, i, j, k)->co, co);
+ }
+ }
+ }
+ if (!odd) {
+ vmesh_center(vm0, center);
+ copy_v3_v3(mesh_vert(vm1, 0, nseg2, nseg2)->co, center);
+ }
+ vmesh_copy_equiv_verts(vm1);
+ return vm1;
+}
+
+/*
+ * Given that the boundary is built and the boundary BMVerts have been made,
+ * calculate the positions of the interior mesh points for the M_ADJ_SUBDIV pattern,
+ * then make the BMVerts and the new faces. */
+static void bevel_build_rings_subdiv(BevelParams *bp, BMesh *bm, BevVert *bv)
+{
+ int n, ns, ns2, odd, i, j, k;
+ VMesh *vm0, *vm1, *vm;
+ float coa[3], cob[3], coc[3];
+ BoundVert *v;
+ BMVert *bmv1, *bmv2, *bmv3, *bmv4;
+ BMFace *f;
+ MemArena *mem_arena = bp->mem_arena;
+ const float fullness = 0.5f;
+
+ n = bv->edgecount;
+ ns = bv->vmesh->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+ BLI_assert(n >= 3 && ns > 1);
+
+ /* First construct an initial control mesh, with nseg==3 */
+ vm0 = new_adj_subdiv_vmesh(mem_arena, n, 3);
+
+ for (i = 0; i < n; i++) {
+ /* Boundaries just divide input polygon edges into 3 even segments */
+ copy_v3_v3(coa, mesh_vert(bv->vmesh, i, 0, 0)->co);
+ copy_v3_v3(cob, mesh_vert(bv->vmesh, (i + 1) % n, 0, 0)->co);
+ copy_v3_v3(coc, mesh_vert(bv->vmesh, (i + n -1) % n, 0, 0)->co);
+ copy_v3_v3(mesh_vert(vm0, i, 0, 0)->co, coa);
+ interp_v3_v3v3(mesh_vert(vm0, i, 0, 1)->co, coa, cob, 1.0f/3.0f);
+ interp_v3_v3v3(mesh_vert(vm0, i, 1, 0)->co, coa, coc, 1.0f/3.0f);
+ interp_v3_v3v3(mesh_vert(vm0, i, 1, 1)->co, coa, bv->v->co, fullness);
+ }
+ vmesh_copy_equiv_verts(vm0);
+
+ vm1 = vm0;
+ do {
+ vm1 = quadratic_subdiv(mem_arena, vm1);
+ /* TODO: readjust vertex positions to make better cross-tangents */
+ } while (vm1->seg < ns);
+ vm1 = interp_vmesh(mem_arena, vm1, ns);
+
+ /* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
+ vm = bv->vmesh;
+ for (i = 0; i < n; i ++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= ns; k++) {
+ if (j == 0 && (k == 0 || k == ns))
+ continue; /* boundary corners already made */
+ if (!is_canon(vm, i, j, k))
+ continue;
+ copy_v3_v3(mesh_vert(vm, i, j, k)->co, mesh_vert(vm1, i, j, k)->co);
+ create_mesh_bmvert(bm, vm, i, j, k, bv->v);
+ }
+ }
+ }
+ vmesh_copy_equiv_verts(vm);
+ /* make the polygons */
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ f = boundvert_rep_face(v);
+ /* For odd ns, make polys with lower left corner at (i,j,k) for
+ * j in [0, ns2-1], k in [0, ns2]. And then the center ngon.
+ * For even ns,
+ * j in [0, ns2-1], k in [0, ns2-1] */
+ for (j = 0; j < ns2; j++) {
+ for (k = 0; k < ns2 + odd; k++) {
+ bmv1 = mesh_vert(vm, i, j, k)->v;
+ bmv2 = mesh_vert(vm, i, j, k + 1)->v;
+ bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v;
+ bmv4 = mesh_vert(vm, i, j + 1, k)->v;
+ BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
+ bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f);
+ }
+ }
+ } while ((v = v->next) != vm->boundstart);
+
+ /* center ngon */
+ if (odd) {
+ BMVert **vv = NULL;
+ BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
+
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
+ } while ((v = v->next) != vm->boundstart);
+ f = boundvert_rep_face(vm->boundstart);
+ bev_create_ngon(bm, vv, BLI_array_count(vv), f);
+
+ BLI_array_free(vv);
+ }
+}
+
static BMFace *bevel_build_poly_ex(BMesh *bm, BevVert *bv)
{
BMFace *f;
@@ -1339,24 +1590,7 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
BoundVert *v, *weld1, *weld2;
int n, ns, ns2, i, k, weld;
float *va, *vb, co[3];
-
-#ifdef USE_ALTERNATE_ADJ
- /* ordered as follows (orig, prev, center, next)*/
- float quad_plane[4][3];
- float quad_orig_a[4][3];
- float quad_orig_b[4][3];
- const int is_odd = (vm->seg % 2);
-#else
float midco[3];
-#endif
-
-#ifdef USE_ALTERNATE_ADJ
- /* the rest are initialized inline, this remains the same for all */
- /* NOTE; in this usage we only interpolate on the 'V' so cent and next points are unused (2,3)*/
- vmesh_cent(vm, quad_plane[2]);
- copy_v3_v3(quad_orig_a[2], bv->v->co);
- copy_v3_v3(quad_orig_b[2], bv->v->co);
-#endif
n = vm->count;
ns = vm->seg;
@@ -1389,59 +1623,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
i = v->index;
copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0);
if (v->ebev) {
-
-#ifdef USE_ALTERNATE_ADJ
- copy_v3_v3(quad_plane[0], v->nv.co);
- mid_v3_v3v3(quad_plane[1], v->nv.co, v->prev->nv.co);
- /* quad[2] is set */
- mid_v3_v3v3(quad_plane[3], v->nv.co, v->next->nv.co);
-
- /* orig 'A' */
- copy_v3_v3(quad_orig_a[0], v->nv.co); /* only shared location between 2 quads */
- project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig_a[1]);
- project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig_a[3]);
-
- /* orig 'B' */
- copy_v3_v3(quad_orig_b[3], v->next->nv.co); /* only shared location between 2 quads */
- project_to_edge(v->ebev->prev->e, v->nv.co, v->prev->nv.co, quad_orig_b[1]);
- project_to_edge(v->ebev->e, v->nv.co, v->next->nv.co, quad_orig_b[0]);
-
- //bl_debug_draw_quad_add(UNPACK4(quad_plane));
- //bl_debug_draw_quad_add(UNPACK4(quad_orig_a));
- //bl_debug_draw_quad_add(UNPACK4(quad_orig_b));
-#endif /* USE_ALTERNATE_ADJ */
-
-#ifdef USE_ALTERNATE_ADJ
- for (k = 1; k < ns; k++) {
- float uv[2];
- float fac;
- float co_plane[3];
- float co_orig[3];
-
- /* quad_plane */
- get_point_uv(uv, v->ebev->seg, 0, k);
- get_point_on_round_edge(uv, quad_plane, co_plane);
-
- /* quad_orig */
- /* each half has different UV's */
- if (k <= ns2) {
- get_point_uv(uv, v->ebev->seg, 0, k);
- get_point_on_round_edge(uv, quad_orig_a, co_orig);
- }
- else {
- get_point_uv(uv, v->ebev->seg, 0, (k - ns2) - (is_odd ? 0.5f : 0.0f));
- get_point_on_round_edge(uv, quad_orig_b, co_orig);
- uv[1] = 1.0f - uv[1]; /* so we can get the factor */
- }
- fac = get_point_uv_factor(uv);
-
- /* done. interp */
- interp_v3_v3v3(co, co_plane, co_orig, fac);
- copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
- if (!weld)
- create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
- }
-#else /* USE_ALTERNATE_ADJ */
va = mesh_vert(vm, i, 0, 0)->co;
vb = mesh_vert(vm, i, 0, ns)->co;
project_to_edge(v->ebev->e, va, vb, midco);
@@ -1451,7 +1632,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
if (!weld)
create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
}
-#endif /* !USE_ALTERNATE_ADJ */
}
} while ((v = v->next) != vm->boundstart);
@@ -1478,6 +1658,9 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
case M_ADJ:
bevel_build_rings(bm, bv);
break;
+ case M_ADJ_SUBDIV:
+ bevel_build_rings_subdiv(bp, bm, bv);
+ break;
case M_TRI_FAN:
bevel_build_trifan(bm, bv);
break;