Four new extrude possibilities;

- Individual faces
  Keeps Mesh manifold, so removes old faces always. Also uses a
  transform based on different vectors per vertex.

- Only edges
  Just extrudes the edges (not really 'individual', the edges still
  share the vertices. Uses same transform as normal extrude for that
  reason

- Only Vertices
  Uses normal transform after extrude

Also changed code a bit, to detect whether to call a normal-based
transform after extrude, or whether to call normal grabber. For example
when you just extrude 1 edge, it uses normal grabber.

Note; extruding an entire sphere goes OK with 'individual faces'. for
other extrudes you should press 's key' when in transform. Just cannot
predict (yet) when one method has preference over another.
This commit is contained in:
Ton Roosendaal 2004-10-18 22:47:26 +00:00
parent 295f11ea70
commit 4c827e73e2
5 changed files with 204 additions and 25 deletions

@ -72,6 +72,9 @@ extern EditFace *exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *
extern void flipface(EditFace *efa); // flips for normal direction
extern int compareface(EditFace *vl1, EditFace *vl2);
extern short extrudeflag_face_indiv(short flag);
extern short extrudeflag_verts_indiv(short flag);
extern short extrudeflag_edges_indiv(short flag);
extern short extrudeflag_vert(short flag);
extern short extrudeflag(short flag);

@ -1199,7 +1199,7 @@ static void texture_panel_image(Tex *tex)
uiDefButS(block, MENU, B_TEXIMABROWSE, strp, 10,135,23,20, &(G.buts->menunr), 0, 0, 0, 0, "Selects an existing texture or creates new");
if(tex->ima) {
uiDefBut(block, TEX, B_NAMEIMA, "", 35,135,255,20, tex->ima->name, 0.0, 79.0, 0, 0, "Displays name of the texture block: click to change");
uiDefBut(block, TEX, B_NAMEIMA, "", 35,135,255,20, tex->ima->name, 0.0, 79.0, 0, 0, "Displays name of the Image file: click to change");
sprintf(str, "%d", tex->ima->id.us);
uiDefBut(block, BUT, 0, str, 290,135,20,20, 0, 0, 0, 0, 0, "Displays number of users of texture: click to make single user");
uiBlockEndAlign(block);

@ -2544,10 +2544,12 @@ static void drawmeshwire_wirextra(DispListMesh *dlm, int optimal, char alpha)
}
else {
/* draw faces twice, to have selected ones on top */
/* we draw unselected the edges though, so they show in face mode */
glColor4ubv(wire);
for(efa= em->faces.first; efa; efa= efa->next) {
if(efa->h==0 && (efa->f & SELECT)==0) {
glVertex_efa_edges(efa);
for(eed= em->edges.first; eed; eed= eed->next) {
if(eed->h==0) {
glVertex3fv(eed->v1->co);
glVertex3fv(eed->v2->co);
}
}
glColor4ubv(sel);

@ -460,6 +460,176 @@ static void set_edge_directions(void)
}
}
/* individual face extrude */
short extrudeflag_face_indiv(short flag)
{
EditMesh *em = G.editMesh;
EditVert *eve, *v1, *v2, *v3, *v4;
EditEdge *eed;
EditFace *efa, *nextfa;
if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
/* selected edges with 1 or more selected face become faces */
/* selected faces each makes new faces */
/* always remove old faces, keeps volumes manifold */
/* select the new extrusion, deselect old */
/* step 1; init, count faces in edges */
recalc_editnormals();
for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
for(eed= em->edges.first; eed; eed= eed->next) {
eed->f2= 0; // amount of unselected faces
}
for(efa= em->faces.first; efa; efa= efa->next) {
if(efa->f & SELECT);
else {
efa->e1->f2++;
efa->e2->f2++;
efa->e3->f2++;
if(efa->e4) efa->e4->f2++;
}
}
/* step 2: make new faces from faces */
for(efa= em->faces.last; efa; efa= efa->prev) {
if(efa->f & SELECT) {
v1= addvertlist(efa->v1->co);
v2= addvertlist(efa->v2->co);
v3= addvertlist(efa->v3->co);
v1->f1= v2->f1= v3->f1= 1;
VECCOPY(v1->no, efa->n);
VECCOPY(v2->no, efa->n);
VECCOPY(v3->no, efa->n);
if(efa->v4) {
v4= addvertlist(efa->v4->co);
v4->f1= 1;
VECCOPY(v4->no, efa->n);
}
else v4= NULL;
/* side faces, clockwise */
addfacelist(efa->v2, v2, v1, efa->v1, efa, NULL);
addfacelist(efa->v3, v3, v2, efa->v2, efa, NULL);
if(efa->v4) {
addfacelist(efa->v4, v4, v3, efa->v3, efa, NULL);
addfacelist(efa->v1, v1, v4, efa->v4, efa, NULL);
}
else {
addfacelist(efa->v1, v1, v3, efa->v3, efa, NULL);
}
/* top face */
addfacelist(v1, v2, v3, v4, efa, NULL);
}
}
/* step 3: remove old faces */
efa= em->faces.first;
while(efa) {
nextfa= efa->next;
if(efa->f & SELECT) {
BLI_remlink(&em->faces, efa);
free_editface(efa);
}
efa= nextfa;
}
/* step 4: redo selection */
EM_clear_flag_all(SELECT);
for(eve= em->verts.first; eve; eve= eve->next) {
if(eve->f1) eve->f |= SELECT;
}
EM_select_flush();
return 'n';
}
/* extrudes individual edges */
short extrudeflag_edges_indiv(short flag)
{
EditMesh *em = G.editMesh;
EditVert *eve;
EditEdge *eed;
EditFace *efa;
float nor[3]={0.0, 0.0, 0.0};
for(eve= em->verts.first; eve; eve= eve->next) eve->vn= NULL;
set_edge_directions();
/* sample for next loop */
for(efa= em->faces.first; efa; efa= efa->next) {
efa->e1->vn= (EditVert *)efa;
efa->e2->vn= (EditVert *)efa;
efa->e3->vn= (EditVert *)efa;
if(efa->e4) efa->e4->vn= (EditVert *)efa;
}
/* make the faces */
for(eed= em->edges.first; eed; eed= eed->next) {
if(eed->f & flag) {
if(eed->v1->vn==NULL) eed->v1->vn= addvertlist(eed->v1->co);
if(eed->v2->vn==NULL) eed->v2->vn= addvertlist(eed->v2->co);
if(eed->dir==1) addfacelist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, (EditFace *)eed->vn, NULL);
else addfacelist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, (EditFace *)eed->vn, NULL);
/* for transform */
if(eed->vn) {
efa= (EditFace *)eed->vn;
if(efa->f & SELECT) VecAddf(nor, nor, efa->n);
}
}
}
Normalise(nor);
/* set correct selection */
EM_clear_flag_all(SELECT);
for(eve= em->verts.last; eve; eve= eve->prev) {
if(eve->vn) {
eve->vn->f |= flag;
VECCOPY(eve->vn->no, nor); // transform() uses it
}
}
for(eed= em->edges.first; eed; eed= eed->next) {
if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
}
if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g';
return 'n';
}
/* extrudes individual vertices */
short extrudeflag_verts_indiv(short flag)
{
EditMesh *em = G.editMesh;
EditVert *eve;
/* make the edges */
for(eve= em->verts.first; eve; eve= eve->next) {
if(eve->f & flag) {
eve->vn= addvertlist(eve->co);
addedgelist(eve, eve->vn, NULL);
}
else eve->vn= NULL;
}
/* set correct selection */
EM_clear_flag_all(SELECT);
for(eve= em->verts.last; eve; eve= eve->prev) if(eve->vn) eve->vn->f |= flag;
return 'g';
}
/* this is actually a recode of extrudeflag(), using proper edge/face select */
/* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */
static short extrudeflag_edge(short flag)
{
/* all select edges/faces: extrude */
@ -467,7 +637,7 @@ static short extrudeflag_edge(short flag)
EditMesh *em = G.editMesh;
EditVert *eve, *nextve;
EditEdge *eed, *nexted;
EditFace *efa, *nextfa, *efa2;
EditFace *efa, *nextfa;
float nor[3]={0.0, 0.0, 0.0};
short del_old= 0;
@ -532,16 +702,8 @@ static short extrudeflag_edge(short flag)
if(eed->v2->vn==NULL)
eed->v2->vn= addvertlist(eed->v2->co);
if(eed->dir==1) efa2= addfacelist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL, NULL);
else efa2= addfacelist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL, NULL);
if(eed->vn) {
/* btw, we dont do it in addfacelist, it copies edges too */
efa= (EditFace *)eed->vn;
efa2->mat_nr= efa->mat_nr;
efa2->tf= efa->tf;
efa2->flag= efa->flag;
}
if(eed->dir==1) addfacelist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, (EditFace *)eed->vn, NULL);
else addfacelist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, (EditFace *)eed->vn, NULL);
}
}
}
@ -620,11 +782,11 @@ static short extrudeflag_edge(short flag)
}
}
Normalise(nor); // translation normal grab
/* step 7: redo selection */
EM_clear_flag_all(SELECT);
Normalise(nor); // translation normal grab
for(eve= em->verts.first; eve; eve= eve->next) {
if(eve->vn) {
eve->vn->f |= SELECT;
@ -634,7 +796,8 @@ static short extrudeflag_edge(short flag)
EM_select_flush();
return 1;
if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g';
return 'n';
}
short extrudeflag_vert(short flag)
@ -856,7 +1019,8 @@ short extrudeflag_vert(short flag)
// since its vertex select mode now, it also deselects higher order
EM_selectmode_flush();
return 1;
if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g';
return 'n';
}
/* generic extrude */

@ -530,21 +530,31 @@ void hashvert_flag(int flag)
void extrude_mesh(void)
{
short a;
short nr, xmode= 0;
TEST_EDITMESH
if(okee("Extrude")==0) return;
if(G.scene->selectmode & SCE_SELECT_VERTEX)
nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
else if(G.scene->selectmode & SCE_SELECT_EDGE)
nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
else
nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
a= extrudeflag(SELECT);
if(nr<1) return;
if(a==0) {
if(nr==1) xmode= extrudeflag(SELECT);
else if(nr==4) xmode= extrudeflag_verts_indiv(SELECT);
else if(nr==3) xmode= extrudeflag_edges_indiv(SELECT);
else xmode= extrudeflag_face_indiv(SELECT);
if(xmode==0) {
error("No valid selection");
}
else {
EM_fgon_flags();
countall();
transform('n');
transform(xmode);
}
}