BEVEL FOR MESH **** LONG LOG WARNING ****

The interesting part:

Bevelling functions for meshes.
Accessible through the Wkey menu.
You then have to enter the recursivity level (Warning, don't use 3 on a big mesh) and interactivly set the bevel width by moving the mouse. It draws the new faces in yellow. Ctrl constraint to 0.1 multiples, Shift switches to low gear, Space to type a value directly.
Support for selective bevelling isn't really working yet, so be sure to select all the vertices beforehand.


The less interesting part:

Code done by intrr (logical stuff, how the algorithm works) and me (math stuff and the interactive bevel width code).

The splitting and bevelling algorithm is not yet fully optimized, and the face shrinking math still doesn't like too big bevel width values. So this will have to be cleaned too.

Selective bevel is on the list next.

If you have any questions about how the code works, send the questions regarding the logic of the method to intrr and math questions to me.


This is very much testing code (or should I say teasing code), so please don't flood me with bug reports. (This excludes OFFICIAL Blender developpers who were there at the meeting and pretty much know what the limitations of the code is and what it should do.)
This commit is contained in:
2003-12-15 04:38:30 +00:00
parent e1d0527cc5
commit ec7c7d6983
3 changed files with 828 additions and 1 deletions

View File

@@ -145,6 +145,8 @@ void sort_faces(void);
void vertices_to_sphere(void); void vertices_to_sphere(void);
void fill_mesh(void); void fill_mesh(void);
void bevel_menu();
/* Editmesh Undo code */ /* Editmesh Undo code */
void undo_free_mesh(struct Mesh *me); void undo_free_mesh(struct Mesh *me);
void undo_push_mesh(char *name); void undo_push_mesh(char *name);

View File

@@ -7751,3 +7751,824 @@ void undo_menu_mesh(void)
if (event==1) remake_editMesh(); if (event==1) remake_editMesh();
else undo_pop_mesh(G.undo_edit_level-event+3); else undo_pop_mesh(G.undo_edit_level-event+3);
} }
/******************* BEVEL CODE STARTS HERE ********************/
void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
{
float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
VecSubf(a, v1, v2);
VecSubf(c, v3, v2);
Crossf(n_a, a, no);
Normalise(n_a);
Crossf(n_c, no, c);
Normalise(n_c);
Normalise(a);
Normalise(c);
ac = Inpf(a, c);
if (ac == 1 || ac == -1) {
midvec[0] = midvec[1] = midvec[2] = 0;
return;
}
ac2 = ac * ac;
fac = sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
VecAddf(mid, n_c, n_a);
Normalise(mid);
VecMulf(mid, d * fac);
VecAddf(mid, mid, v2);
VecCopyf(midvec, mid);
}
/* Finds the new point using the sinus law to extrapolate a triangle
Lots of sqrts which would not be good for a real time algo
Using the mid point of the extrapolation of both sides
Useless for coplanar quads, but that doesn't happen too often */
void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3]) {
float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
VecSubf(a, v3, v2);
l_a = Normalise(a);
VecSubf(b, v4, v3);
Normalise(b);
VecSubf(c, v1, v2);
Normalise(c);
s_b = Inpf(a, c);
s_b = sqrt(1 - (s_b * s_b));
s_a = Inpf(b, c);
s_a = sqrt(1 - (s_a * s_a));
VecMulf(a, -1);
s_c = Inpf(a, b);
s_c = sqrt(1 - (s_c * s_c));
l_b = s_b * l_a / s_a;
l_c = s_c * l_a / s_a;
VecMulf(b, l_b);
VecMulf(c, l_c);
VecAddf(Pos1, v2, c);
VecAddf(Pos2, v3, b);
VecAddf(Dir, Pos1, Pos2);
VecMulf(Dir, 0.5);
bevel_displace_vec(midvec, v3, Dir, v2, d, no);
}
// Detects a quad partial wrapping after the resize
char detect_partial_wrap(float *v1, float *v2, float *v3, float no[3]) {
float tri_no[3], a[3], c[3];
VecSubf(a, v1, v2);
VecSubf(c, v3, v2);
Crossf(tri_no, c, a);
if (Inpf(no, tri_no) < 0)
return 1;
else
return 0;
}
char detect_axial_quad_wrap(float *orig_edge_v1, float *orig_edge_v2, float *edge_v1, float *edge_v2, float *other_edge_v1, float *other_edge_v2) {
float orig_mid[3], mid[3], other_mid[3], vec1[3], vec2[3];
VecAddf(orig_mid, orig_edge_v1, orig_edge_v2);
VecAddf(mid, edge_v1, edge_v2);
VecAddf(other_mid, other_edge_v1, other_edge_v2);
VecSubf(vec1, orig_mid, mid);
VecSubf(vec2, other_mid, mid);
if (vec2[0] == 0 && vec2[1] == 0 && vec2[2] == 0)
return 0;
if (Inpf(vec1, vec2) >= 0)
return 1;
else
return 0;
}
// Detects and fix a quad wrapping after the resize
// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float no[3]) {
float vec[3];
char wrap[4];
char Axis1, Axis2;
// Quads can wrap partially. Watch out
wrap[0] = detect_partial_wrap(v4, v1, v2, no);
wrap[1] = detect_partial_wrap(v1, v2, v3, no);
wrap[2] = detect_partial_wrap(v2, v3, v4, no);
wrap[3] = detect_partial_wrap(v3, v4, v1, no);
if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
VECCOPY(v1, vec);
VECCOPY(v2, vec);
}
else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 0) {
fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
VECCOPY(v2, vec);
VECCOPY(v3, vec);
}
else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 1) {
fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
VECCOPY(v3, vec);
VECCOPY(v4, vec);
}
else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
VECCOPY(v4, vec);
VECCOPY(v1, vec);
}
else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1){
// even though the whole face could be inverted, doesn't mean it's inverted on all axis
Axis1 = detect_axial_quad_wrap(o_v1, o_v2, v1, v2, v3, v4);
Axis2 = detect_axial_quad_wrap(o_v2, o_v3, v2, v3, v4, v1);
// Inverted on one of the axis
if (Axis1==1 && Axis2==0) {
VecAddf(vec, v2, v3);
VecMulf(vec, 0.5);
VECCOPY(v2, vec);
VECCOPY(v3, vec);
VecAddf(vec, v1, v4);
VecMulf(vec, 0.5);
VECCOPY(v1, vec);
VECCOPY(v4, vec);
}
// Inverted on the other axis
else if (Axis1==0 && Axis2==1) {
VecAddf(vec, v1, v2);
VecMulf(vec, 0.5);
VECCOPY(v1, vec);
VECCOPY(v2, vec);
VecAddf(vec, v3, v4);
VecMulf(vec, 0.5);
VECCOPY(v3, vec);
VECCOPY(v4, vec);
}
// Totally inverted
else if (Axis1==1 && Axis2==1) {
VecAddf(vec, v1, v2);
VecAddf(vec, vec, v3);
VecAddf(vec, vec, v4);
VecMulf(vec, 0.25);
VECCOPY(v1, vec);
VECCOPY(v2, vec);
VECCOPY(v3, vec);
VECCOPY(v4, vec);
}
}
printf("\n");
}
// Detects and fix a tri wrapping after the resize
// Arguments are the orginal verts followed by the final verts
void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3) {
float a[3], b[3];
VecSubf(a, o_v1, v1);
VecSubf(b, v2, v1);
if (Inpf(a, b) >= 0) {
float vec[3];
VecAddf(vec, o_v1, o_v2);
VecAddf(vec, vec, o_v3);
VecMulf(vec, 1.0/3.0);
VECCOPY(v1, vec);
VECCOPY(v2, vec);
VECCOPY(v3, vec);
}
}
void bevel_shrink_faces(float d, int flag)
{
EditVlak *evl;
float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
/* move edges of all faces with evl->f1 & flag closer towards their centres */
evl= G.edvl.first;
while (evl) {
VECCOPY(v1, evl->v1->co);
VECCOPY(v2, evl->v2->co);
VECCOPY(v3, evl->v3->co);
VECCOPY(no, evl->n);
if (evl->v4 == NULL) {
bevel_displace_vec(vec, v1, v2, v3, d, no);
VECCOPY(evl->v2->co, vec);
bevel_displace_vec(vec, v2, v3, v1, d, no);
VECCOPY(evl->v3->co, vec);
bevel_displace_vec(vec, v3, v1, v2, d, no);
VECCOPY(evl->v1->co, vec);
fix_bevel_tri_wrap(v1, v2, v3, evl->v1->co, evl->v2->co, evl->v3->co);
} else {
VECCOPY(v4, evl->v4->co);
bevel_displace_vec(vec, v1, v2, v3, d, no);
VECCOPY(evl->v2->co, vec);
bevel_displace_vec(vec, v2, v3, v4, d, no);
VECCOPY(evl->v3->co, vec);
bevel_displace_vec(vec, v3, v4, v1, d, no);
VECCOPY(evl->v4->co, vec);
bevel_displace_vec(vec, v4, v1, v2, d, no);
VECCOPY(evl->v1->co, vec);
fix_bevel_quad_wrap(v1, v2, v3, v4, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co, d, no);
}
evl= evl->next;
}
}
void bevel_shrink_draw(float d, int flag)
{
EditVlak *evl;
float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
/* move edges of all faces with evl->f1 & flag closer towards their centres */
evl= G.edvl.first;
while (evl) {
VECCOPY(v1, evl->v1->co);
VECCOPY(v2, evl->v2->co);
VECCOPY(v3, evl->v3->co);
VECCOPY(no, evl->n);
if (evl->v4 == NULL) {
bevel_displace_vec(vec, v1, v2, v3, d, no);
VECCOPY(fv2, vec);
bevel_displace_vec(vec, v2, v3, v1, d, no);
VECCOPY(fv3, vec);
bevel_displace_vec(vec, v3, v1, v2, d, no);
VECCOPY(fv1, vec);
fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3);
glBegin(GL_LINES);
glVertex3fv(fv1);
glVertex3fv(fv2);
glEnd();
glBegin(GL_LINES);
glVertex3fv(fv2);
glVertex3fv(fv3);
glEnd();
glBegin(GL_LINES);
glVertex3fv(fv1);
glVertex3fv(fv3);
glEnd();
} else {
VECCOPY(v4, evl->v4->co);
bevel_displace_vec(vec, v1, v2, v3, d, no);
VECCOPY(fv2, vec);
bevel_displace_vec(vec, v2, v3, v4, d, no);
VECCOPY(fv3, vec);
bevel_displace_vec(vec, v3, v4, v1, d, no);
VECCOPY(fv4, vec);
bevel_displace_vec(vec, v4, v1, v2, d, no);
VECCOPY(fv1, vec);
fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
glBegin(GL_LINES);
glVertex3fv(fv1);
glVertex3fv(fv2);
glEnd();
glBegin(GL_LINES);
glVertex3fv(fv2);
glVertex3fv(fv3);
glEnd();
glBegin(GL_LINES);
glVertex3fv(fv3);
glVertex3fv(fv4);
glEnd();
glBegin(GL_LINES);
glVertex3fv(fv1);
glVertex3fv(fv4);
glEnd();
}
evl= evl->next;
}
}
void bevel_shrink_faces_test()
{
EditVlak *evl;
evl= G.edvl.first;
while (evl) {
evl->f1 |= 1;
evl= evl->next;
}
bevel_shrink_faces(0.1, 1);
}
void bevel_mesh(float bsize, int allfaces)
{
//#define BEV_DEBUG
/* Enables debug printfs and assigns material indices: */
/* 2 = edge quad */
/* 3 = fill polygon (vertex clusters) */
EditVlak *evl, *nextvl, *example;
EditEdge *eed, *eed2;
EditVert *neweve[1024], *eve, *eve2, *eve3, *eve4, *v1, *v2, *v3, *v4;
float con1, con2, con3;
short found4, search;
float f1, f2, f3, f4;
float cent[3], min[3], max[3];
int a, b, c;
float limit= 0.001;
waitcursor(1);
removedoublesflag(1, limit);
/* tag all original faces */
evl= G.edvl.first;
while (evl) {
if (vlakselectedAND(evl, 1)||allfaces) {
evl->f1= 1;
evl->v1->f |= 128;
evl->v2->f |= 128;
evl->v3->f |= 128;
if (evl->v4) evl->v4->f |= 128;
}
evl->v1->f &= ~64;
evl->v2->f &= ~64;
evl->v3->f &= ~64;
if (evl->v4) evl->v4->f &= ~64;
evl= evl->next;
}
#ifdef BEV_DEBUG
fprintf(stderr,"bevel_mesh: split\n");
#endif
evl= G.edvl.first;
while (evl) {
if (evl->f1 & 1) {
evl->f1-= 1;
v1= addvertlist(evl->v1->co);
v1->f= evl->v1->f & ~128;
evl->v1->vn= v1;
#ifdef __NLA
v1->totweight = evl->v1->totweight;
if (evl->v1->totweight){
v1->dw = MEM_mallocN (evl->v1->totweight * sizeof(MDeformWeight), "deformWeight");
memcpy (v1->dw, evl->v1->dw, evl->v1->totweight * sizeof(MDeformWeight));
}
else
v1->dw=NULL;
#endif
v1= addvertlist(evl->v2->co);
v1->f= evl->v2->f & ~128;
evl->v2->vn= v1;
#ifdef __NLA
v1->totweight = evl->v2->totweight;
if (evl->v2->totweight){
v1->dw = MEM_mallocN (evl->v2->totweight * sizeof(MDeformWeight), "deformWeight");
memcpy (v1->dw, evl->v2->dw, evl->v2->totweight * sizeof(MDeformWeight));
}
else
v1->dw=NULL;
#endif
v1= addvertlist(evl->v3->co);
v1->f= evl->v3->f & ~128;
evl->v3->vn= v1;
#ifdef __NLA
v1->totweight = evl->v3->totweight;
if (evl->v3->totweight){
v1->dw = MEM_mallocN (evl->v3->totweight * sizeof(MDeformWeight), "deformWeight");
memcpy (v1->dw, evl->v3->dw, evl->v3->totweight * sizeof(MDeformWeight));
}
else
v1->dw=NULL;
#endif
if (evl->v4) {
v1= addvertlist(evl->v4->co);
v1->f= evl->v4->f & ~128;
evl->v4->vn= v1;
#ifdef __NLA
v1->totweight = evl->v4->totweight;
if (evl->v4->totweight){
v1->dw = MEM_mallocN (evl->v4->totweight * sizeof(MDeformWeight), "deformWeight");
memcpy (v1->dw, evl->v4->dw, evl->v4->totweight * sizeof(MDeformWeight));
}
else
v1->dw=NULL;
#endif
}
addedgelist(evl->e1->v1->vn,evl->e1->v2->vn);
addedgelist(evl->e2->v1->vn,evl->e2->v2->vn);
addedgelist(evl->e3->v1->vn,evl->e3->v2->vn);
if (evl->e4) addedgelist(evl->e4->v1->vn,evl->e4->v2->vn);
if(evl->v4) {
v1= evl->v1->vn;
v2= evl->v2->vn;
v3= evl->v3->vn;
v4= evl->v4->vn;
addvlaklist(v1, v2, v3, v4, evl);
} else {
v1= evl->v1->vn;
v2= evl->v2->vn;
v3= evl->v3->vn;
addvlaklist(v1, v2, v3, 0, evl);
}
evl= evl-> next;
} else {
evl= evl->next;
}
}
delvlakflag(128);
/* tag all faces for shrink*/
evl= G.edvl.first;
while (evl) {
if (vlakselectedAND(evl, 1)||allfaces) evl->f1= 2;
evl= evl->next;
}
#ifdef BEV_DEBUG
fprintf(stderr,"bevel_mesh: make edge quads\n");
#endif
/* find edges that are on each other and make quads between them */
eed= G.eded.first;
while(eed) {
eed->f= eed->f1= 0;
if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces) eed->f1 |= 4; /* original edges */
eed->vn= 0;
eed= eed->next;
}
eed= G.eded.first;
while (eed) {
if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
eed2= G.eded.first;
while (eed2) {
if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
if (
(eed->v1 != eed2->v1) &&
(eed->v1 != eed2->v2) &&
(eed->v2 != eed2->v1) &&
(eed->v2 != eed2->v2) && (
( VecCompare(eed->v1->co, eed2->v1->co, limit) &&
VecCompare(eed->v2->co, eed2->v2->co, limit) ) ||
( VecCompare(eed->v1->co, eed2->v2->co, limit) &&
VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) )
{
#ifdef BEV_DEBUG
fprintf(stderr, "bevel_mesh: edge quad\n");
#endif
eed->f1 |= 2; /* these edges are finished */
eed2->f1 |= 2;
example= NULL;
evl= G.edvl.first; /* search example vlak (for mat_nr, ME_SMOOTH, ...) */
while (evl) {
if ( (evl->e1 == eed) ||
(evl->e2 == eed) ||
(evl->e3 == eed) ||
(evl->e4 && (evl->e4 == eed)) ) {
example= evl;
evl= NULL;
}
if (evl) evl= evl->next;
}
neweve[0]= eed->v1; neweve[1]= eed->v2;
neweve[2]= eed2->v1; neweve[3]= eed2->v2;
if(exist_vlak(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
evl= NULL;
if (VecCompare(eed->v1->co, eed2->v2->co, limit)) {
evl= addvlaklist(neweve[0], neweve[1], neweve[2], neweve[3], example);
} else {
evl= addvlaklist(neweve[0], neweve[2], neweve[3], neweve[1], example);
}
if(evl) {
float inp;
CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, evl->n);
inp= evl->n[0]*G.vd->viewmat[0][2] + evl->n[1]*G.vd->viewmat[1][2] + evl->n[2]*G.vd->viewmat[2][2];
if(inp < 0.0) flipvlak(evl);
#ifdef BEV_DEBUG
evl->mat_nr= 1;
#endif
} else fprintf(stderr,"bevel_mesh: error creating face\n");
}
eed2= NULL;
}
}
if (eed2) eed2= eed2->next;
}
}
eed= eed->next;
}
eed= G.eded.first;
while(eed) {
eed->f= eed->f1= 0;
eed->f1= 0;
eed->v1->f1 &= ~1;
eed->v2->f1 &= ~1;
eed->vn= 0;
eed= eed->next;
}
#ifdef BEV_DEBUG
fprintf(stderr,"bevel_mesh: find clusters\n");
#endif
/* Look for vertex clusters */
eve= G.edve.first;
while (eve) {
eve->f &= ~(64|128);
eve->vn= NULL;
eve= eve->next;
}
/* eve->f: 128: first vertex in a list (->vn) */
/* 64: vertex is in a list */
eve= G.edve.first;
while (eve) {
eve2= G.edve.first;
eve3= NULL;
while (eve2) {
if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
if (VecCompare(eve->co, eve2->co, limit)) {
if ((eve->f & (128|64)) == 0) {
/* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
eve->f |= 128;
eve->vn= eve2;
eve3= eve2;
} else if ((eve->f & 64) == 0) {
/* fprintf(stderr," *\n"); */
if (eve3) eve3->vn= eve2;
eve2->f |= 64;
eve3= eve2;
}
}
}
eve2= eve2->next;
if (!eve2) {
if (eve3) eve3->vn= NULL;
}
}
eve= eve->next;
}
#ifdef BEV_DEBUG
fprintf(stderr,"bevel_mesh: shrink faces\n");
#endif
bevel_shrink_faces(bsize, 2);
#ifdef BEV_DEBUG
fprintf(stderr,"bevel_mesh: fill clusters\n");
#endif
/* Make former vertex clusters faces */
eve= G.edve.first;
while (eve) {
eve->f &= ~64;
eve= eve->next;
}
eve= G.edve.first;
while (eve) {
if (eve->f & 128) {
eve->f &= ~128;
a= 0;
neweve[a]= eve;
eve2= eve->vn;
while (eve2) {
a++;
neweve[a]= eve2;
eve2= eve2->vn;
}
a++;
evl= NULL;
if (a>=3) {
example= NULL;
evl= G.edvl.first; /* search example vlak */
while (evl) {
if ( (evl->v1 == neweve[0]) ||
(evl->v2 == neweve[0]) ||
(evl->v3 == neweve[0]) ||
(evl->v4 && (evl->v4 == neweve[0])) ) {
example= evl;
evl= NULL;
}
if (evl) evl= evl->next;
}
#ifdef BEV_DEBUG
fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
#endif
if (a>4) {
cent[0]= cent[1]= cent[2]= 0.0;
INIT_MINMAX(min, max);
for (b=0; b<a; b++) {
VecAddf(cent, cent, neweve[b]->co);
DO_MINMAX(neweve[b]->co, min, max);
}
cent[0]= (min[0]+max[0])/2;
cent[1]= (min[1]+max[1])/2;
cent[2]= (min[2]+max[2])/2;
eve2= addvertlist(cent);
eve2->f |= 1;
eed= G.eded.first;
while (eed) {
c= 0;
for (b=0; b<a; b++)
if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
if (c==2) {
if(exist_vlak(eed->v1, eed->v2, eve2, 0)==0) {
evl= addvlaklist(eed->v1, eed->v2, eve2, 0, example);
#ifdef BEV_DEBUG
evl->mat_nr= 2;
#endif
}
}
eed= eed->next;
}
} else if (a==4) {
if(exist_vlak(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
if(con1>=con2 && con1>=con3)
evl= addvlaklist(neweve[0], neweve[1], neweve[2], neweve[3], example);
else if(con2>=con1 && con2>=con3)
evl= addvlaklist(neweve[0], neweve[2], neweve[3], neweve[1], example);
else
evl= addvlaklist(neweve[0], neweve[2], neweve[1], neweve[3], example);
}
}
else if (a==3) {
if(exist_vlak(neweve[0], neweve[1], neweve[2], 0)==0)
evl= addvlaklist(neweve[0], neweve[1], neweve[2], 0, example);
}
if(evl) {
float inp;
CalcNormFloat(neweve[0], neweve[1], neweve[2], evl->n);
inp= evl->n[0]*G.vd->viewmat[0][2] + evl->n[1]*G.vd->viewmat[1][2] + evl->n[2]*G.vd->viewmat[2][2];
if(inp < 0.0) flipvlak(evl);
#ifdef BEV_DEBUG
evl->mat_nr= 2;
#endif
}
}
}
eve= eve->next;
}
eve= G.edve.first;
while (eve) {
eve->f1= 0;
eve->f &= ~(128|64);
eve->vn= NULL;
eve= eve->next;
}
recalc_editnormals();
waitcursor(0);
countall();
allqueue(REDRAWVIEW3D, 0);
makeDispList(G.obedit);
removedoublesflag(1, limit);
#undef BEV_DEBUG
}
void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
{
float d;
short nr;
d= bsize;
for (nr=0; nr<recurs; nr++) {
bevel_mesh(d, allfaces);
if (nr==0) d /= 3; else d /= 2;
}
}
void bevel_menu()
{
EditVlak *evl;
char Finished = 0, Canceled = 0;
short mval[2], oval[2], curval[2], event = 0, recurs = 1;
float vec[3], d, drawd, centre[3];
char str[100];
getmouseco_areawin(mval);
curval[0] = oval[0] = mval[0];
curval[1] = oval[1] = mval[1];
window_to_3d(centre, mval[0], mval[1]);
if(button(&recurs, 1, 4, "Recurs:")==0) return;
while (Finished == 0)
{
short nr;
getmouseco_areawin(mval);
if (mval[0] != curval[0] || mval[1] != curval[1])
{
curval[0] = mval[0];
curval[1] = mval[1];
window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
d = Normalise(vec) / 10;
if (G.qual & LR_CTRLKEY)
d = (float) floor(d * 10.0)/10.0;
if (G.qual & LR_SHIFTKEY)
d /= 10;
drawd = d;
for (nr=0; nr<recurs-1; nr++) {
if (nr==0) drawd += drawd/3; else drawd += drawd/2;
}
/*------------- Preview lines--------------- */
/* uses callback mechanism to draw it all in current area */
scrarea_do_windraw(curarea);
/* set window matrix to perspective, default an area returns with buttons transform */
persp(PERSP_VIEW);
/* make a copy, for safety */
glPushMatrix();
/* multiply with the object transformation */
mymultmatrix(G.obedit->obmat);
glColor3ub(255, 255, 0);
// PREVIEW CODE GOES HERE
bevel_shrink_draw(drawd, 2);
/* restore matrix transform */
glPopMatrix();
sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
headerprint(str);
/* this also verifies other area/windows for clean swap */
screen_swapbuffers();
persp(PERSP_WIN);
glDrawBuffer(GL_FRONT);
BIF_ThemeColor(TH_WIRE);
setlinestyle(3);
glBegin(GL_LINE_STRIP);
glVertex2sv(mval);
glVertex2sv(oval);
glEnd();
setlinestyle(0);
persp(PERSP_VIEW);
glFinish(); // flush display for frontbuffer
glDrawBuffer(GL_BACK);
}
while(qtest()) {
unsigned short val=0;
event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
/* val==0 on key-release event */
if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)){
if (event==RIGHTMOUSE || event==ESCKEY)
Canceled = 1;
Finished = 1;
}
else if (val && event==SPACEKEY) {
if (fbutton(&d, 0.000, 10.000, "Width:")!=0)
Finished = 1;
}
}
}
if (Canceled==0) {
bevel_mesh_recurs(d, recurs, 1);
}
}

View File

@@ -1556,7 +1556,7 @@ void special_editmenu(void)
} }
else if(G.obedit->type==OB_MESH) { else if(G.obedit->type==OB_MESH) {
nr= pupmenu("Specials%t|Subdivide%x1|Subdivide Fractal%x2|Subdivide Smooth%x3|Merge%x4|Remove Doubles%x5|Hide%x6|Reveal%x7|Select swap%x8|Flip Normals %x9|Smooth %x10"); nr= pupmenu("Specials%t|Subdivide%x1|Subdivide Fractal%x2|Subdivide Smooth%x3|Merge%x4|Remove Doubles%x5|Hide%x6|Reveal%x7|Select swap%x8|Flip Normals %x9|Smooth %x10|Bevel %x11");
if(nr>0) waitcursor(1); if(nr>0) waitcursor(1);
switch(nr) { switch(nr) {
@@ -1600,6 +1600,10 @@ void special_editmenu(void)
undo_push_mesh("Smooth"); undo_push_mesh("Smooth");
vertexsmooth(); vertexsmooth();
break; break;
case 11:
undo_push_mesh("Bevel");
bevel_menu();
break;
} }
makeDispList(G.obedit); makeDispList(G.obedit);