Commit: 49aa701645e97ea7a6f698e4063a5327f6c79815
Author: Howard Trickey
Date:   Wed Jan 8 07:40:01 2014 -0500
https://developer.blender.org/rB49aa701645e97ea7a6f698e4063a5327f6c79815

Add profile control parameter to Bevel.

Parameter controls concavity / convexity.
    <.25 means: concave inward
    .25 means: straight slanted
    >.25 means: concave outward
    .5 means: circular (the default)
    1 means: straight along original sides
For now, there is a hard lower limit of .15
because more work is needed to get decent
results in the range below that.

The profile is actually a superellipse, and the
parameter is 1/4 of the exponent in the implicit equation
for a superellipse, except at the extreme values of 0 and 1.

===================================================================

M       source/blender/bmesh/intern/bmesh_opdefines.c
M       source/blender/bmesh/operators/bmo_bevel.c
M       source/blender/bmesh/tools/bmesh_bevel.c
M       source/blender/bmesh/tools/bmesh_bevel.h
M       source/blender/editors/mesh/editmesh_bevel.c
M       source/blender/modifiers/intern/MOD_bevel.c

===================================================================

diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c 
b/source/blender/bmesh/intern/bmesh_opdefines.c
index 97624ec..b469793 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1559,6 +1559,7 @@ static BMOpDefine bmo_bevel_def = {
         {"offset", BMO_OP_SLOT_FLT},           /* amount to offset beveled 
edge */
         {"offset_type", BMO_OP_SLOT_INT},      /* how to measure offset (enum) 
*/
         {"segments", BMO_OP_SLOT_INT},         /* number of segments in bevel 
*/
+        {"profile", BMO_OP_SLOT_FLT},          /* profile shape, 0->1 
(.5=>round) */
         {"vertex_only", BMO_OP_SLOT_BOOL},     /* only bevel vertices, not 
edges */
         {{'\0'}},
        },
diff --git a/source/blender/bmesh/operators/bmo_bevel.c 
b/source/blender/bmesh/operators/bmo_bevel.c
index 4eec15d..07a2e67 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -39,6 +39,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
        const int   offset_type = BMO_slot_int_get(op->slots_in,   
"offset_type");
        const int   seg         = BMO_slot_int_get(op->slots_in,   "segments");
        const bool  vonly       = BMO_slot_bool_get(op->slots_in,  
"vertex_only");
+       const float profile     = BMO_slot_float_get(op->slots_in, "profile");
 
        if (offset > 0) {
                BMOIter siter;
@@ -59,7 +60,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
                        }
                }
 
-               BM_mesh_bevel(bm, offset, offset_type, seg, vonly, false, 
false, NULL, -1);
+               BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, 
false, false, NULL, -1);
 
                BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, 
"faces.out", BM_FACE, BM_ELEM_TAG);
        }
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c 
b/source/blender/bmesh/tools/bmesh_bevel.c
index 984632d..4a6032a 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -89,14 +89,20 @@ typedef struct EdgeHalf {
 } EdgeHalf;
 
 /* Profile specification.
- * For now, only have round profiles and straight profiles, so only need 
midpoint.
+ * Many interesting profiles are in family of superellipses:
+ *     (abs(x/a))^r + abs(y/b))^r = 1
+ * r==2 => ellipse; r==1 => line; r < 1 => concave; r > 1 => bulging out.
+ * Special cases: let r==0 mean straight-inward, and r==4 mean straight outward
  * The start and end points of the profile are stored separately.
- * TODO: generalize to superellipse profiles.
  */
 typedef struct Profile {
-       bool flat;
+       float super_r;       /* superellipse r parameter */
        float midco[3];      /* mid control point for profile */
 } Profile;
+#define PRO_SQUARE_R 4.0f
+#define PRO_CIRCLE_R 2.0f
+#define PRO_LINE_R 1.0f
+#define PRO_SQUARE_IN_R 0.0f
 
 /* An element in a cyclic boundary of a Vertex Mesh (VMesh) */
 typedef struct BoundVert {
@@ -150,6 +156,7 @@ typedef struct BevelParams {
        float offset;           /* blender units to offset each side of a 
beveled edge */
        int offset_type;        /* how offset is measured; enum defined in 
bmesh_operators.h */
        int seg;                /* number of segments in beveled edge profile */
+       float pro_super_r;      /* superellipse parameter for edge profile */
        bool vertex_only;       /* bevel vertices only */
        bool use_weights;       /* bevel amount affected by weights on edges or 
verts */
        bool preserve_widths;   /* should bevel prefer widths over angles, if 
forced to choose? */
@@ -182,7 +189,7 @@ static BoundVert *add_new_bound_vert(MemArena *mem_arena, 
VMesh *vm, const float
                tail->next = ans;
                vm->boundstart->prev = ans;
        }
-       ans->profile.flat = true;
+       ans->profile.super_r = PRO_LINE_R;
        vm->count++;
        return ans;
 }
@@ -825,13 +832,13 @@ static void project_to_edge(BMEdge *e, const float 
co_a[3], const float co_b[3],
 /* If there is a bndv->ebev edge, find the mid control point if necessary.
  * It is the closest point on the beveled edge to the line segment between
  * bndv and bndv->next.  */
-static void set_profile_params(BoundVert *bndv)
+static void set_profile_params(BevelParams *bp, BoundVert *bndv)
 {
        EdgeHalf *e;
 
        e = bndv->ebev;
        if (e) {
-               bndv->profile.flat = false;
+               bndv->profile.super_r = bp->pro_super_r;
                project_to_edge(e->e, bndv->nv.co, bndv->next->nv.co,
                                bndv->profile.midco);
        }
@@ -1001,23 +1008,46 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
 /* Find the point on given profile at parameter u which goes from 0 to 2 as
  * the profile is moved from va to vb. */
 static void get_profile_point(const Profile *pro, const float va[3], const 
float vb[3], float u, float r_co[3])
- {
-       float p[3], angle;
+{
+       float p[3], vo[3], angle, r, w;
        float m[4][4];
 
        if (u <= 0.0f)
                copy_v3_v3(r_co, va);
        else if (u >= 2.0f)
                copy_v3_v3(r_co, vb);
-       else if (pro->flat || !make_unit_square_map(va, pro->midco, vb, m)) {
-               interp_v3_v3v3(r_co, va, vb, u / 2.0f);
-       }
        else {
-               angle = u * (float)M_PI / 4.0f;  /* angle from y axis */
-               p[0] = sinf(angle);
-               p[1] = cosf(angle);
-               p[2] = 0.0f;
-               mul_v3_m4v3(r_co, m, p);
+               r = pro->super_r;
+               if (r == 1.0f || !make_unit_square_map(va, pro->midco, vb, m)) {
+                       interp_v3_v3v3(r_co, va, vb, u / 2.0f);
+               }
+               else if (r == PRO_SQUARE_IN_R) {
+                       /* square inward concave */
+                       zero_v3(p);
+                       mul_v3_m4v3(vo, m, p);
+                       if (u <= 1.0f)
+                               interp_v3_v3v3(r_co, va, vo, u);
+                       else
+                               interp_v3_v3v3(r_co, vo, vb, u - 1.0f);
+               }
+               else if (r >= PRO_SQUARE_R) {
+                       /* square outward convex */
+                       if (u <= 1.0f)
+                               interp_v3_v3v3(r_co, va, pro->midco, u);
+                       else
+                               interp_v3_v3v3(r_co, pro->midco, vb, u - 1.0f);
+        }
+               else {
+                       angle = u * (float)M_PI / 4.0f;  /* angle from y axis */
+                       p[0] = sinf(angle);
+                       p[1] = cosf(angle);
+                       p[2] = 0.0f;
+                       if (r != PRO_CIRCLE_R) {
+                               w = powf(powf(p[0], r) + pow(p[1], r), -1.0f / 
r);
+                               mul_v2_fl(p, w);
+                       }
+                       mul_v3_m4v3(r_co, m, p);
+               }
        }
 }
 
@@ -1065,11 +1095,43 @@ static void snap_to_edge_profile(EdgeHalf *e, const 
float va[3], const float vb[
 }
 #endif
 
-/* Snapping a direction co to a unit radius sphere is just normalizing co.
- * TODO: generalize to superellipsoid */
-static void snap_to_sphere(float co[3])
+/* Snap a direction co to a superellipsoid with parameter super_r */
+static void snap_to_superellipsoid(float co[3], const float super_r)
 {
-       normalize_v3(co);
+       float a, b, c, x, y, z, r, rinv;
+
+       r = super_r;
+       if (r == PRO_CIRCLE_R) {
+               normalize_v3(co);
+               return;
+       }
+
+       x = a = max_ff(0.0f, co[0]);
+       y = b = max_ff(0.0f, co[1]);
+       z = c = max_ff(0.0f, co[2]);
+       if (r <= 0.0f)
+               r = 0.1f;
+       rinv = 1.0f / r;
+       if (a == 0.0f) {
+               if (b == 0.0f) {
+                       x = 0.0f;
+                       y = 0.0f;
+                       z = powf(c, rinv);
+               }
+               else {
+                       x = 0.0f;
+                       y = powf(1.0f / (1.0f + powf(c / b, r)), rinv);
+                       z = c * y / b;
+               }
+       }
+       else {
+               x = powf(1.0f / (1.0f + powf(b / a, r) + powf(c / a, r)), rinv);
+               y = b * x / a;
+               z = c * x / a;
+       }
+       co[0] = x;
+       co[1] = y;
+       co[2] = z;
 }
 
 static void snap_to_profile(BoundVert *bndv, EdgeHalf *e, float co[3])
@@ -1087,14 +1149,14 @@ static void snap_to_profile(BoundVert *bndv, EdgeHalf 
*e, float co[3])
        closest_to_plane_v3(vb0, plane, vb);
        closest_to_plane_v3(vmid0, plane, bndv->profile.midco);
        if (make_unit_square_map(va0, vmid0, vb0, m)) {
-               /* Transform co and project it onto sphere */
+               /* Transform co and project it onto superellipse */
                if (!invert_m4_m4(minv, m)) {
                        /* shouldn't happen */
                        BLI_assert(!"failed inverse during profile snap");
                        return;
                }
                mul_v3_m4v3(p, minv, co);
-               snap_to_sphere(p);
+               snap_to_superellipsoid(p, bndv->profile.super_r);
                mul_v3_m4v3(snap, m, p);
                copy_v3_v3(co, snap);
        }
@@ -1207,7 +1269,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, 
bool construct)
                else {
                        adjust_bound_vert(e->next->leftv, co);
                }
-               set_profile_params(vm->boundstart);
+               set_profile_params(bp, vm->boundstart);
                return;
        }
 
@@ -1311,7 +1373,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, 
bool construct)
 
        v = vm->boundstart;
        do {
-               set_profile_params(v);
+               set_profile_params(bp, v);
        } while ((v = v->next) != vm->boundstart);
 
        if (bv->selcount == 1 && bv->edgecount == 3) {
@@ -2247,12 +2309,44 @@ static VMesh *cubic_subdiv(MemArena *mem_arena, VMesh 
*vm0)
        return vm1;
 }
 
+/* Special case for cube corner, when r is PRO_SQUARE_R,
+ * meaning straight sides */
+static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg)
+{
+       VMesh *vm;
+       float co[3];
+       int i, j, k, ns2;
+
+    ns2 = nseg / 2;
+       vm = new_adj_subdiv_vmesh(mem_arena, 3, nseg, NULL);
+       vm->count = 0;  // reset, so following loop will end up with correct 
count
+       for (i = 0; i < 3; i++) {
+               zero_v3(co);
+               co[i] = 1.0f;
+               add_new_bound_vert(mem_arena, vm, co);
+       }
+       for (i = 0; i < 3; i++) {
+               for (j = 0; j <= ns2; j++) {
+                       for (k = 0; k <= ns2; k++) {
+                               if (!is_canon(vm, i, j, k))
+                                       continue;
+                               co[i] = 1.0f;
+                               co[(i + 1) % 3] = (float) k * 2.0 / (float) 
nseg;
+                               co[(i + 2) % 3] = (float) j * 2.0 / (float) 
nseg;
+                               copy_v3_v3(mesh_vert(vm, i, j, k)->co, co);
+                       }
+               }
+       }
+       vmesh_copy_equiv_verts(vm);
+       return vm;
+}
+
 /* Make a VMesh with nseg segments that covers the unit radius sphere octant
  * with center at (0,0,0).
  * This has BoundVerts at (1,0,0), (0,1,0) and (0,0,1), with quarter circle 
arcs
  * on the faces for the orthogonal planes through the origin.
  */
-static VMesh *make_cube_corner_adj_vmesh(MemArena *mem_arena, int nseg)
+static VMesh *make_cube_corner_adj_vmesh(MemArena *mem_arena, int nseg, float 
r)
 {
        VMesh *vm0, *vm1;
        BoundVert *bndv;
@@ -2260,6 +2354,9 @@ static VMesh *make_cube_corner_adj_vmesh(MemArena 
*mem_arena, int nseg)
        float co[3], coa[3], cob[3], coc[3];
        float w;
 
+       if (r == PRO_SQUARE_R)
+               return make_cube_corner_straight(mem_arena, nseg);
+
        /* initial mesh has 3 sides, 2 segments */
        vm0 = new_adj_subdiv_vmesh(mem_arena, 3, 2, NULL);
        vm0->count = 0;  // reset, so following loop will end up with correct 
count
@@ -2276,6 +2373,7 @@ static VMesh *make_cube_corner_adj_vmesh(MemArena 
*mem_arena, int nseg)
                coc[i] = 1.0f;
                coc[(i + 1) % 3] = 1.0f;
                coc[(i + 2) % 3] = 0.0f;
+               bndv->profile.super_r = r;
                copy_v

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to