== Sculpt Mode ==
authorNicholas Bishop <nicholasbishop@gmail.com>
Wed, 14 Mar 2007 20:00:01 +0000 (20:00 +0000)
committerNicholas Bishop <nicholasbishop@gmail.com>
Wed, 14 Mar 2007 20:00:01 +0000 (20:00 +0000)
* Added new brush, "Flatten". This brush pushes vertices along the normal defined by the average normal of each vertex within the brush area. The vertices are pushed towards the plane defined by vertices towards the edge of the brush. Essentially, this means that the direction of flattening is dependent on the surface beneath the brush.

* In order to make space for the flatten brush, the controls inside the Sculpt palette were widened to 268. (Note that the panel width didn't change, so it still fits properly in the vertical layout.)

* Todo: it would probably make sense to make the "View" slider available under the Brush tab available for the Flatten brush (currently it's only used for the Draw brush.)

source/blender/makesdna/DNA_scene_types.h
source/blender/src/buttons_editing.c
source/blender/src/header_view3d.c
source/blender/src/sculptmode.c

index df99c5c531e9285751bde4dd66d652c0ffb1c3c9..99f4cc109448f1a0934cdac283984f2e08873f60 100644 (file)
@@ -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
index c5fdb5648842574d4cd6fb3c8973f817dfa07e59..aea738c09065e4ce30e278a7ef67baa28270c979 100644 (file)
@@ -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;
index fc02b236cdfa8ad3ed0374b4d51a0cfcdcb4fb02..d41359fcf43181a0822eee79e3c32c64eb840889 100644 (file)
@@ -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, "");
index 53ac5467445a8dc3eeb795b47cc44cdf461ebcd1..ce46b631510f7e8b7779c2be8497544c90a92a12 100644 (file)
@@ -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;
-       }
+       /* 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);
+               /* 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;
        }