diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index df99c5c531e..99f4cc10944 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -373,7 +373,7 @@ typedef struct SculptData struct MTex *mtex[10]; /* Settings for each brush */ - BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush; + BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush, flattenbrush; short brush_type; /* For the Brush Shape */ @@ -605,6 +605,7 @@ typedef struct Scene { #define INFLATE_BRUSH 4 #define GRAB_BRUSH 5 #define LAYER_BRUSH 6 +#define FLATTEN_BRUSH 7 /* SculptData.texrept */ #define SCULPTREPT_DRAG 1 #define SCULPTREPT_TILE 2 diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index c5fdb564884..aea738c0906 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -4451,11 +4451,12 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned uiBlockBeginAlign(block); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Draw",cx,cy,67,19,&sd->brush_type,14.0,DRAW_BRUSH,0,0,"Draw lines on the model"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Smooth",cx+67,cy,67,19,&sd->brush_type,14.0,SMOOTH_BRUSH,0,0,"Interactively smooth areas of the model"); - uiDefButS(block,ROW,REDRAWBUTSEDIT,"Pinch",cx+134,cy,66,19,&sd->brush_type,14.0,PINCH_BRUSH,0,0,"Interactively pinch areas of the model"); + uiDefButS(block,ROW,REDRAWBUTSEDIT,"Pinch",cx+134,cy,67,19,&sd->brush_type,14.0,PINCH_BRUSH,0,0,"Interactively pinch areas of the model"); + uiDefButS(block,ROW,REDRAWBUTSEDIT,"Inflate",cx+201,cy,67,19,&sd->brush_type,14,INFLATE_BRUSH,0,0,"Push vertices along the direction of their normals"); cy-= 20; - uiDefButS(block,ROW,REDRAWBUTSEDIT,"Inflate",cx,cy,67,19,&sd->brush_type,14,INFLATE_BRUSH,0,0,"Push vertices along the direction of their normals"); - uiDefButS(block,ROW,REDRAWBUTSEDIT,"Grab", cx+67,cy,67,19,&sd->brush_type,14,GRAB_BRUSH,0,0,"Grabs a group of vertices and moves them with the mouse"); - uiDefButS(block,ROW,REDRAWBUTSEDIT,"Layer", cx+134,cy,66,19,&sd->brush_type,14, LAYER_BRUSH,0,0,"Adds a layer of depth"); + uiDefButS(block,ROW,REDRAWBUTSEDIT,"Grab", cx,cy,89,19,&sd->brush_type,14,GRAB_BRUSH,0,0,"Grabs a group of vertices and moves them with the mouse"); + uiDefButS(block,ROW,REDRAWBUTSEDIT,"Layer", cx+89,cy,89,19,&sd->brush_type,14, LAYER_BRUSH,0,0,"Adds a layer of depth"); + uiDefButS(block,ROW,REDRAWBUTSEDIT,"Flatten", cx+178,cy,90,19,&sd->brush_type,14, FLATTEN_BRUSH,0,0,"Interactively flatten areas of the model"); cy-= 25; uiBlockEndAlign(block); @@ -4463,17 +4464,17 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned uiDefBut(block,LABEL,B_NOP,"Shape",cx,cy,90,19,NULL,0,0,0,0,""); cy-= 20; uiBlockBeginAlign(block); - if(sd->brush_type!=SMOOTH_BRUSH && sd->brush_type!=GRAB_BRUSH) { - uiDefButC(block,ROW,B_NOP,"Add",cx,cy,67,19,&sculptmode_brush()->dir,15.0,1.0,0, 0,"Add depth to model [Shift]"); - uiDefButC(block,ROW,B_NOP,"Sub",cx+67,cy,67,19,&sculptmode_brush()->dir,15.0,2.0,0, 0,"Subtract depth from model [Shift]"); + if(sd->brush_type != SMOOTH_BRUSH && sd->brush_type != GRAB_BRUSH && sd->brush_type != FLATTEN_BRUSH) { + uiDefButC(block,ROW,B_NOP,"Add",cx,cy,89,19,&sculptmode_brush()->dir,15.0,1.0,0, 0,"Add depth to model [Shift]"); + uiDefButC(block,ROW,B_NOP,"Sub",cx+89,cy,89,19,&sculptmode_brush()->dir,15.0,2.0,0, 0,"Subtract depth from model [Shift]"); } if(sd->brush_type!=GRAB_BRUSH) - uiDefButC(block,TOG,B_NOP,"Airbrush",cx+134,cy,66,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move"); + uiDefButC(block,TOG,B_NOP,"Airbrush",cx+178,cy,89,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move"); cy-= 20; - but= uiDefButS(block,NUMSLI,B_NOP,"Size: ",cx,cy,200,19,&sculptmode_brush()->size,1.0,200.0,0,0,"Set brush radius in pixels"); + but= uiDefButS(block,NUMSLI,B_NOP,"Size: ",cx,cy,268,19,&sculptmode_brush()->size,1.0,200.0,0,0,"Set brush radius in pixels"); cy-= 20; if(sd->brush_type!=GRAB_BRUSH) - uiDefButC(block,NUMSLI,B_NOP,"Strength: ",cx,cy,200,19,&sculptmode_brush()->strength,1.0,100.0,0,0,"Set brush strength"); + uiDefButC(block,NUMSLI,B_NOP,"Strength: ",cx,cy,268,19,&sculptmode_brush()->strength,1.0,100.0,0,0,"Set brush strength"); cy-= 25; uiBlockEndAlign(block); @@ -4481,9 +4482,9 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned uiDefBut( block,LABEL,B_NOP,"Symmetry",cx,cy,90,19,NULL,0,0,0,0,""); cy-= 20; uiBlockBeginAlign(block); - uiDefButBitC(block, TOG, SYMM_X, 0, "X", cx,cy,67,19, &sd->symm, 0,0,0,0, "Mirror brush across X axis"); - uiDefButBitC(block, TOG, SYMM_Y, 0, "Y", cx+67,cy,67,19, &sd->symm, 0,0,0,0, "Mirror brush across Y axis"); - uiDefButBitC(block, TOG, SYMM_Z, 0, "Z", cx+134,cy,67,19, &sd->symm, 0,0,0,0, "Mirror brush across Z axis"); + uiDefButBitC(block, TOG, SYMM_X, 0, "X", cx,cy,89,19, &sd->symm, 0,0,0,0, "Mirror brush across X axis"); + uiDefButBitC(block, TOG, SYMM_Y, 0, "Y", cx+89,cy,89,19, &sd->symm, 0,0,0,0, "Mirror brush across Y axis"); + uiDefButBitC(block, TOG, SYMM_Z, 0, "Z", cx+178,cy,90,19, &sd->symm, 0,0,0,0, "Mirror brush across Z axis"); uiBlockEndAlign(block); cx+= 210; diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index fc02b236cdf..d41359fcf43 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -4117,10 +4117,9 @@ void do_view3d_sculptmenu(void *arg, int event) case 3: case 4: case 5: + case 6: sd->brush_type= event+1; break; - case 6: - br->dir= br->dir==1 ? 2 : 1; break; case 7: br->airbrush= !br->airbrush; break; case 8: @@ -4151,6 +4150,8 @@ void do_view3d_sculptmenu(void *arg, int event) case 17: sculptmode_propset_init(PropsetSize); break; + case 18: + br->dir= br->dir==1 ? 2 : 1; break; } allqueue(REDRAWBUTSEDIT, 0); @@ -4208,11 +4209,12 @@ uiBlock *view3d_sculptmenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, (br->airbrush ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Airbrush|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); - if(sd->brush_type!=SMOOTH_BRUSH) { - uiDefIconTextBut(block, BUTM, 1, (br->dir==1 ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Add|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); + if(sd->brush_type!=SMOOTH_BRUSH && sd->brush_type!=FLATTEN_BRUSH) { + uiDefIconTextBut(block, BUTM, 1, (br->dir==1 ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Add|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, ""); } } uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==FLATTEN_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Flatten", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==LAYER_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Layer|L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==GRAB_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Grab|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==INFLATE_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Inflate|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); diff --git a/source/blender/src/sculptmode.c b/source/blender/src/sculptmode.c index 53ac5467445..ce46b631510 100644 --- a/source/blender/src/sculptmode.c +++ b/source/blender/src/sculptmode.c @@ -115,6 +115,7 @@ typedef struct ActiveData { struct ActiveData *next, *prev; unsigned int Index; float Fade; + float dist; } ActiveData; typedef struct GrabData { @@ -195,10 +196,17 @@ void sculptmode_init(Scene *sce) memset(sd, 0, sizeof(SculptData)); - sd->drawbrush.size=sd->smoothbrush.size=sd->pinchbrush.size=sd->inflatebrush.size=sd->grabbrush.size=sd->layerbrush.size= 50; - sd->drawbrush.strength=sd->smoothbrush.strength=sd->pinchbrush.strength=sd->inflatebrush.strength=sd->grabbrush.strength=sd->layerbrush.strength= 25; - sd->drawbrush.dir=sd->pinchbrush.dir=sd->inflatebrush.dir=sd->layerbrush.dir= 1; - sd->drawbrush.airbrush=sd->smoothbrush.airbrush=sd->pinchbrush.airbrush=sd->inflatebrush.airbrush=sd->layerbrush.airbrush= 0; + sd->drawbrush.size = sd->smoothbrush.size = sd->pinchbrush.size = + sd->inflatebrush.size = sd->grabbrush.size = + sd->layerbrush.size = sd->flattenbrush.size = 50; + sd->drawbrush.strength = sd->smoothbrush.strength = + sd->pinchbrush.strength = sd->inflatebrush.strength = + sd->grabbrush.strength = sd->layerbrush.strength = + sd->flattenbrush.strength = 25; + sd->drawbrush.dir = sd->pinchbrush.dir = sd->inflatebrush.dir = sd->layerbrush.dir= 1; + sd->drawbrush.airbrush = sd->smoothbrush.airbrush = + sd->pinchbrush.airbrush = sd->inflatebrush.airbrush = + sd->layerbrush.airbrush = sd->flattenbrush.airbrush = 0; sd->drawbrush.view= 0; sd->brush_type= DRAW_BRUSH; sd->texact= -1; @@ -430,6 +438,8 @@ float brush_strength(EditData *e) return 1; case INFLATE_BRUSH: return b->strength / 5000.0f * dir * pressure * flip; + case FLATTEN_BRUSH: + return b->strength / 500.0f * pressure; default: return 0; } @@ -647,6 +657,62 @@ void do_inflate_brush(const EditData *e, const ListBase *active_verts) } } +void calc_flatten_center(Mesh *me, ActiveData *node, const EditData *e, float co[3]) +{ + const int FTOT = 10; + ActiveData *outer[FTOT]; + int i; + + for(i = 0; i < FTOT; ++i) + outer[i] = node; + + for(; node; node = node->next) { + for(i = 0; i < FTOT; ++i) { + if(node->dist > outer[i]->dist) { + outer[i] = node; + break; + } + } + } + + co[0] = co[1] = co[2] = 0.0f; + for(i = 0; i < FTOT; ++i) + VecAddf(co, co, me->mvert[outer[i]->Index].co); + VecMulf(co, 1.0f / FTOT); +} + +void do_flatten_brush(const EditData *e, const ListBase *active_verts) +{ + Mesh *me= get_mesh(OBACT); + ActiveData *node= active_verts->first; + /* area_normal and cntr define the plane towards which vertices are squashed */ + vec3f area_normal= calc_area_normal(&e->out, active_verts); + float cntr[3]; + + calc_flatten_center(me, node, e, cntr); + + while(node){ + float *co= me->mvert[node->Index].co; + float p1[3], sub1[3], sub2[3], intr[3], val[3]; + + /* Find the intersection between squash-plane and vertex (along the area normal) */ + VecSubf(p1, co, &area_normal.x); + VecSubf(sub1, cntr, p1); + VecSubf(sub2, co, p1); + VecSubf(intr, co, p1); + VecMulf(intr, Inpf(&area_normal.x, sub1) / Inpf(&area_normal.x, sub2)); + VecAddf(intr, intr, p1); + + VecSubf(val, intr, co); + VecMulf(val, node->Fade); + VecAddf(val, val, co); + + sculpt_clip(e, co, val); + + node= node->next; + } +} + /* Creates a smooth curve for the brush shape. This is the cos(x) curve from [0,PI] scaled to [0,len]. The range is scaled to [0,1]. */ float simple_strength(float p, const float len) @@ -857,6 +923,7 @@ void do_brush_action(float *vertexcosnos, EditData e, /* Fade is used to store the final strength at which the brush should modify a particular vertex. */ adata->Fade= tex_strength(&e,vert,av_dist,i) * bstrength; + adata->dist = av_dist; if(e.grabdata && e.grabdata->firsttime) BLI_addtail(&e.grabdata->active_verts[e.grabdata->index], adata); else @@ -866,44 +933,50 @@ void do_brush_action(float *vertexcosnos, EditData e, } } - /* Apply one type of brush action */ - switch(G.scene->sculptdata.brush_type){ - case DRAW_BRUSH: - do_draw_brush(&e, &active_verts); - break; - case SMOOTH_BRUSH: - do_smooth_brush(&e, &active_verts); - break; - case PINCH_BRUSH: - do_pinch_brush(&e, &active_verts); - break; - case INFLATE_BRUSH: - do_inflate_brush(&e, &active_verts); - break; - case GRAB_BRUSH: - do_grab_brush(&e); - break; - case LAYER_BRUSH: - do_layer_brush(&e, &active_verts); - break; - } - - /* Copy the modified vertices from mesh to the active key */ - if(keyblock) { - float *co= keyblock->data; - if(co) { - adata = e.grabdata ? e.grabdata->active_verts[e.grabdata->index].first : active_verts.first; - for(; adata; adata= adata->next) - if(adata->Index < keyblock->totelem) - VecCopyf(&co[adata->Index*3], me->mvert[adata->Index].co); + /* Only act if some verts are inside the brush area */ + if(active_verts.first || (e.grabdata && e.grabdata->active_verts[e.grabdata->index].first)) { + /* Apply one type of brush action */ + switch(G.scene->sculptdata.brush_type){ + case DRAW_BRUSH: + do_draw_brush(&e, &active_verts); + break; + case SMOOTH_BRUSH: + do_smooth_brush(&e, &active_verts); + break; + case PINCH_BRUSH: + do_pinch_brush(&e, &active_verts); + break; + case INFLATE_BRUSH: + do_inflate_brush(&e, &active_verts); + break; + case GRAB_BRUSH: + do_grab_brush(&e); + break; + case LAYER_BRUSH: + do_layer_brush(&e, &active_verts); + break; + case FLATTEN_BRUSH: + do_flatten_brush(&e, &active_verts); + break; + } + + /* Copy the modified vertices from mesh to the active key */ + if(keyblock) { + float *co= keyblock->data; + if(co) { + adata = e.grabdata ? e.grabdata->active_verts[e.grabdata->index].first : active_verts.first; + for(; adata; adata= adata->next) + if(adata->Index < keyblock->totelem) + VecCopyf(&co[adata->Index*3], me->mvert[adata->Index].co); + } } - } - if(vertexcosnos) - BLI_freelistN(&active_verts); - else { - if(!e.grabdata) - addlisttolist(damaged_verts, &active_verts); + if(vertexcosnos) + BLI_freelistN(&active_verts); + else { + if(!e.grabdata) + addlisttolist(damaged_verts, &active_verts); + } } } @@ -1014,7 +1087,8 @@ BrushData *sculptmode_brush(void) sd->brush_type==PINCH_BRUSH ? &sd->pinchbrush : sd->brush_type==INFLATE_BRUSH ? &sd->inflatebrush : sd->brush_type==GRAB_BRUSH ? &sd->grabbrush : - sd->brush_type==LAYER_BRUSH ? &sd->layerbrush : NULL); + sd->brush_type==LAYER_BRUSH ? &sd->layerbrush : + sd->brush_type==FLATTEN_BRUSH ? &sd->flattenbrush : NULL); } void sculptmode_update_tex() @@ -1399,7 +1473,7 @@ void sculptmode_selectbrush_menu(void) pupmenu_set_active(sd->brush_type); - val= pupmenu("Select Brush%t|Draw|Smooth|Pinch|Inflate|Grab|Layer"); + val= pupmenu("Select Brush%t|Draw|Smooth|Pinch|Inflate|Grab|Layer|Flatten"); if(val>0) { sd->brush_type= val; @@ -1730,6 +1804,8 @@ void sculpt(void) BIF_undo_push("Grab Brush"); break; case LAYER_BRUSH: BIF_undo_push("Layer Brush"); break; + case FLATTEN_BRUSH: + BIF_undo_push("Flatten Brush"); break; default: BIF_undo_push("Sculpting"); break; }