== Sculpt ==
authorNicholas Bishop <nicholasbishop@gmail.com>
Fri, 25 Jan 2008 04:17:38 +0000 (04:17 +0000)
committerNicholas Bishop <nicholasbishop@gmail.com>
Fri, 25 Jan 2008 04:17:38 +0000 (04:17 +0000)
Cleaned up some old parts of sculpt. Got rid of the old EditData struct in favor of two new "brush action" structures, which split the symmetry data out from everything else. Cleaned up various names and such as well. There should be no user-visible changes.

source/blender/include/BDR_sculptmode.h
source/blender/src/sculptmode-stroke.c
source/blender/src/sculptmode.c

index 8b0b65be4dea655121eba318efac778c6bec9b47..e36b867461295e5a598f002423e959819cf8cc05 100644 (file)
@@ -35,8 +35,8 @@
 #include "BKE_sculpt.h"
 
 struct uiBlock;
+struct BrushAction;
 struct BrushData;
-struct EditData;
 struct IndexNode;
 struct KeyBlock;
 struct Mesh;
@@ -65,7 +65,7 @@ void sculpt_stroke_draw();
 void sculpt_radialcontrol_start(int mode);
 
 struct BrushData *sculptmode_brush(void);
-void do_symmetrical_brush_actions(struct EditData *e, short *, short *);
+void do_symmetrical_brush_actions(struct BrushAction *a, short *, short *);
 
 void sculptmode_update_tex(void);
 char sculpt_modifiers_active(struct Object *ob);
@@ -76,8 +76,8 @@ void set_sculptmode(void);
 void sculpt_stroke_new(const int max);
 void sculpt_stroke_free();
 void sculpt_stroke_add_point(const short x, const short y);
-void sculpt_stroke_apply(struct EditData *);
-void sculpt_stroke_apply_all(struct EditData *e);
+void sculpt_stroke_apply(struct BrushAction *);
+void sculpt_stroke_apply_all(struct BrushAction *);
 void sculpt_stroke_draw();
 
 
index c2c96b04a1d07788eef1849826a73ee23614a8c4..69c20eeeddf2a641eefd3192b9c1fd915d0d38ff 100644 (file)
@@ -178,7 +178,7 @@ float sculpt_stroke_final_length(SculptStroke *stroke)
 }
 
 /* If partial is nonzero, cuts off apply after that length has been processed */
-static StrokePoint *sculpt_stroke_apply_generic(SculptStroke *stroke, struct EditData *e, const int partial)
+static StrokePoint *sculpt_stroke_apply_generic(SculptStroke *stroke, struct BrushAction *a, const int partial)
 {
        const int sdspace = sculpt_data()->spacing;
        const short spacing = sdspace > 0 ? sdspace : 2;
@@ -215,13 +215,13 @@ static StrokePoint *sculpt_stroke_apply_generic(SculptStroke *stroke, struct Edi
                co[0] = p->x*v + p->next->x*u;
                co[1] = p->y*v + p->next->y*u;
 
-               do_symmetrical_brush_actions(e, co, NULL);
+               do_symmetrical_brush_actions(a, co, NULL);
        }
 
        return p ? p->next : NULL;
 }
 
-void sculpt_stroke_apply(struct EditData *e)
+void sculpt_stroke_apply(struct BrushAction *a)
 {
        SculptStroke *stroke = sculpt_session()->stroke;
        /* TODO: make these values user-modifiable? */
@@ -232,7 +232,7 @@ void sculpt_stroke_apply(struct EditData *e)
                sculpt_stroke_create_final();
 
                if(sculpt_stroke_final_length(stroke) > min_len) {
-                       StrokePoint *p = sculpt_stroke_apply_generic(stroke, e, partial_len);
+                       StrokePoint *p = sculpt_stroke_apply_generic(stroke, a, partial_len);
 
                        /* Replace remaining values in stroke->loc with remaining stroke->final values */
                        stroke->index = -1;
@@ -249,14 +249,14 @@ void sculpt_stroke_apply(struct EditData *e)
        }
 }
 
-void sculpt_stroke_apply_all(struct EditData *e)
+void sculpt_stroke_apply_all(struct BrushAction *a)
 {
        SculptStroke *stroke = sculpt_session()->stroke;
 
        sculpt_stroke_create_final();
 
        if(stroke) {
-               sculpt_stroke_apply_generic(stroke, e, 0);
+               sculpt_stroke_apply_generic(stroke, a, 0);
        }
 }
 
index 9e1fa16a44c4422f69cb7c3b5fe90df348d433d9..dbefadb2646cc2eb40238856bfeafbc23237dda6 100644 (file)
@@ -125,36 +125,39 @@ typedef struct ActiveData {
        float dist;
 } ActiveData;
 
-typedef struct GrabData {
-       char firsttime;
-       ListBase active_verts[8];
-       unsigned char index;
-       vec3f delta, delta_symm;
-       float depth;
-} GrabData;
+typedef struct BrushActionSymm {
+       float center_3d[3];
+       char index;
 
-typedef struct EditData {
-       vec3f center;
-       float size;
-       char flip;
-       short mouse[2];
+       float up[3], right[3], out[3];
 
-       /* Adjust brush strength along each axis
-          to adjust for object scaling */
-       float scale[3];
+       // Grab brush
+       float grab_delta[3];
+} BrushActionSymm;
 
-       /* View normals */
-       vec3f up, right, out;
+typedef struct BrushAction {
+       BrushActionSymm symm;
+
+       char firsttime;
+
+       short mouse[2];
+       float size_3d;
 
-       GrabData *grabdata;
        float *layer_disps;
        vec3f *layer_store;
-       
+       char flip;
+
        char clip[3];
        float cliptol[3];
-       
-       char symm;
-} EditData;
+
+       // Grab brush
+       ListBase grab_active_verts[8];
+       float depth;
+
+       /* Adjust brush strength along each axis
+          to adjust for object scaling */
+       float scale[3];
+} BrushAction;
 
 typedef struct RectNode {
        struct RectNode *next, *prev;
@@ -178,7 +181,7 @@ SculptData *sculpt_data(void)
 }
 
 void sculpt_init_session(void);
-void init_editdata(EditData *e, short *, short *);
+void init_brushaction(BrushAction *a, short *, short *);
 void sculpt_undo_push(const short);
 
 SculptSession *sculpt_session(void)
@@ -294,18 +297,16 @@ float get_depth(short x, short y)
 
 /* Uses window coordinates (x,y) and depth component z to find a point in
    modelspace */
-vec3f unproject(const short x, const short y, const float z)
+void unproject(float out[3], const short x, const short y, const float z)
 {
        SculptSession *ss= sculpt_session();
        double ux, uy, uz;
-       vec3f p;
 
         gluUnProject(x,y,z, ss->mats->modelview, ss->mats->projection,
                     (GLint *)ss->mats->viewport, &ux, &uy, &uz );
-       p.x= ux;
-       p.y= uy;
-       p.z= uz;
-       return p;
+       out[0] = ux;
+       out[1] = uy;
+       out[2] = uz;
 }
 
 /* Convert a point in model coordinates to 2D screen coordinates. */
@@ -348,13 +349,13 @@ char brush_size()
 /* Return modified brush strength. Includes the direction of the brush, positive
    values pull vertices, negative values push. Uses tablet pressure and a
    special multiplier found experimentally to scale the strength factor. */
-float brush_strength(EditData *e)
+float brush_strength(BrushAction *a)
 {
        const BrushData* b= sculptmode_brush();
        float dir= b->dir==1 ? 1 : -1;
        float pressure= 1;
        short activedevice= get_activedevice();
-       float flip= e->flip ? -1:1;
+       float flip= a->flip ? -1:1;
 
        const float strength_factor= G.scene->sculptdata.tablet_strength / 10.0f;
        if(ELEM(activedevice, DEV_STYLUS, DEV_ERASER))
@@ -385,11 +386,11 @@ float brush_strength(EditData *e)
 }
 
 /* For clipping against a mirror modifier */
-void sculpt_clip(const EditData *e, float *co, const float val[3])
+void sculpt_clip(const BrushAction *a, float *co, const float val[3])
 {
        char i;
        for(i=0; i<3; ++i) {
-               if(e->clip[i] && (fabs(co[i]) <= e->cliptol[i]))
+               if(a->clip[i] && (fabs(co[i]) <= a->cliptol[i]))
                        co[i]= 0.0f;
                else
                        co[i]= val[i];
@@ -398,7 +399,7 @@ void sculpt_clip(const EditData *e, float *co, const float val[3])
 
 /* Currently only for the draw brush; finds average normal for all active
    vertices */
-vec3f calc_area_normal(const vec3f *outdir, const ListBase* active_verts)
+vec3f calc_area_normal(const float *outdir, const ListBase* active_verts)
 {
        Mesh *me= get_mesh(OBACT);
        vec3f area_normal= {0,0,0};
@@ -412,28 +413,30 @@ vec3f calc_area_normal(const vec3f *outdir, const ListBase* active_verts)
                node= node->next;
        }
        Normalize(&area_normal.x);
+
        if(outdir) {
-               area_normal.x= outdir->x * view + area_normal.x * (10-view);
-               area_normal.y= outdir->y * view + area_normal.y * (10-view);
-               area_normal.z= outdir->z * view + area_normal.z * (10-view);
+               area_normal.x= outdir[0] * view + area_normal.x * (10-view);
+               area_normal.y= outdir[1] * view + area_normal.y * (10-view);
+               area_normal.z= outdir[2] * view + area_normal.z * (10-view);
        }
+
        Normalize(&area_normal.x);
        return area_normal;
 }
-void do_draw_brush(const EditData *e, const ListBase* active_verts)
+void do_draw_brush(const BrushAction *a, const ListBase* active_verts)
 {
        Mesh *me= get_mesh(OBACT);
-       const vec3f area_normal= calc_area_normal(&e->out, active_verts);
+       const vec3f area_normal= calc_area_normal(a->symm.out, active_verts);
        ActiveData *node= active_verts->first;
 
        while(node){
                float *co= me->mvert[node->Index].co;
                
-               const float val[3]= {co[0]+area_normal.x*node->Fade*e->scale[0],
-                                    co[1]+area_normal.y*node->Fade*e->scale[1],
-                                    co[2]+area_normal.z*node->Fade*e->scale[2]};
+               const float val[3]= {co[0]+area_normal.x*node->Fade*a->scale[0],
+                                    co[1]+area_normal.y*node->Fade*a->scale[1],
+                                    co[2]+area_normal.z*node->Fade*a->scale[2]};
                                     
-               sculpt_clip(e, co, val);
+               sculpt_clip(a, co, val);
                
                node= node->next;
        }
@@ -489,7 +492,7 @@ vec3f neighbor_average(const int vert)
        return avg;
 }
 
-void do_smooth_brush(const EditData *e, const ListBase* active_verts)
+void do_smooth_brush(const BrushAction *a, const ListBase* active_verts)
 {
        ActiveData *node= active_verts->first;
        Mesh *me= get_mesh(OBACT);
@@ -500,53 +503,53 @@ void do_smooth_brush(const EditData *e, const ListBase* active_verts)
                const float val[3]= {co[0]+(avg.x-co[0])*node->Fade,
                                     co[1]+(avg.y-co[1])*node->Fade,
                                     co[2]+(avg.z-co[2])*node->Fade};
-               sculpt_clip(e, co, val);
+               sculpt_clip(a, co, val);
                node= node->next;
        }
 }
 
-void do_pinch_brush(const EditData *e, const ListBase* active_verts)
+void do_pinch_brush(const BrushAction *a, const ListBase* active_verts)
 {
        Mesh *me= get_mesh(OBACT);
        ActiveData *node= active_verts->first;
 
        while(node) {
                float *co= me->mvert[node->Index].co;
-               const float val[3]= {co[0]+(e->center.x-co[0])*node->Fade,
-                                    co[1]+(e->center.y-co[1])*node->Fade,
-                                    co[2]+(e->center.z-co[2])*node->Fade};
-               sculpt_clip(e, co, val);
+               const float val[3]= {co[0]+(a->symm.center_3d[0]-co[0])*node->Fade,
+                                    co[1]+(a->symm.center_3d[1]-co[1])*node->Fade,
+                                    co[2]+(a->symm.center_3d[2]-co[2])*node->Fade};
+               sculpt_clip(a, co, val);
                node= node->next;
        }
 }
 
-void do_grab_brush(EditData *e)
+void do_grab_brush(BrushAction *a)
 {
        Mesh *me= get_mesh(OBACT);
-       ActiveData *node= e->grabdata->active_verts[e->grabdata->index].first;
+       ActiveData *node= a->grab_active_verts[a->symm.index].first;
        float add[3];
 
        while(node) {
                float *co= me->mvert[node->Index].co;
                
-               VecCopyf(add, &e->grabdata->delta_symm.x);
+               VecCopyf(add, a->symm.grab_delta);
                VecMulf(add, node->Fade);
                VecAddf(add, add, co);
-               sculpt_clip(e, co, add);
+               sculpt_clip(a, co, add);
 
                node= node->next;
        }
 }
 
-void do_layer_brush(EditData *e, const ListBase *active_verts)
+void do_layer_brush(BrushAction *a, const ListBase *active_verts)
 {
        Mesh *me= get_mesh(OBACT);
        vec3f area_normal= calc_area_normal(NULL, active_verts);
        ActiveData *node= active_verts->first;
-       const float bstr= brush_strength(e);
+       const float bstr= brush_strength(a);
 
        while(node){
-               float *disp= &e->layer_disps[node->Index];
+               float *disp= &a->layer_disps[node->Index];
                
                if((bstr > 0 && *disp < bstr) ||
                  (bstr < 0 && *disp > bstr)) {
@@ -563,10 +566,10 @@ void do_layer_brush(EditData *e, const ListBase *active_verts)
                        }
 
                        {
-                               const float val[3]= {e->layer_store[node->Index].x+area_normal.x * *disp*e->scale[0],
-                                                    e->layer_store[node->Index].y+area_normal.y * *disp*e->scale[1],
-                                                    e->layer_store[node->Index].z+area_normal.z * *disp*e->scale[2]};
-                               sculpt_clip(e, co, val);
+                               const float val[3]= {a->layer_store[node->Index].x+area_normal.x * *disp*a->scale[0],
+                                                    a->layer_store[node->Index].y+area_normal.y * *disp*a->scale[1],
+                                                    a->layer_store[node->Index].z+area_normal.z * *disp*a->scale[2]};
+                               sculpt_clip(a, co, val);
                        }
                }
 
@@ -574,7 +577,7 @@ void do_layer_brush(EditData *e, const ListBase *active_verts)
        }
 }
 
-void do_inflate_brush(const EditData *e, const ListBase *active_verts)
+void do_inflate_brush(const BrushAction *a, const ListBase *active_verts)
 {
        ActiveData *node= active_verts->first;
        float add[3];
@@ -588,18 +591,18 @@ void do_inflate_brush(const EditData *e, const ListBase *active_verts)
                add[1]= no[1]/ 32767.0f;
                add[2]= no[2]/ 32767.0f;
                VecMulf(add, node->Fade);
-               add[0]*= e->scale[0];
-               add[1]*= e->scale[1];
-               add[2]*= e->scale[2];
+               add[0]*= a->scale[0];
+               add[1]*= a->scale[1];
+               add[2]*= a->scale[2];
                VecAddf(add, add, co);
                
-               sculpt_clip(e, co, add);
+               sculpt_clip(a, co, add);
 
                node= node->next;
        }
 }
 
-void calc_flatten_center(Mesh *me, ActiveData *node, const EditData *e, float co[3])
+void calc_flatten_center(Mesh *me, ActiveData *node, float co[3])
 {
        ActiveData *outer[FLATTEN_SAMPLE_SIZE];
        int i;
@@ -622,15 +625,15 @@ void calc_flatten_center(Mesh *me, ActiveData *node, const EditData *e, float co
        VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE);
 }
 
-void do_flatten_brush(const EditData *e, const ListBase *active_verts)
+void do_flatten_brush(const BrushAction *a, 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);
+       vec3f area_normal= calc_area_normal(a->symm.out, active_verts);
        float cntr[3];
        
-       calc_flatten_center(me, node, e, cntr);
+       calc_flatten_center(me, node, cntr);
 
        while(node){
                float *co= me->mvert[node->Index].co;
@@ -648,7 +651,7 @@ void do_flatten_brush(const EditData *e, const ListBase *active_verts)
                VecMulf(val, node->Fade);
                VecAddf(val, val, co);
                                     
-               sculpt_clip(e, co, val);
+               sculpt_clip(a, co, val);
                
                node= node->next;
        }
@@ -709,7 +712,7 @@ unsigned *get_texcache_pixel(const SculptSession *ss, int px, int py)
 }
 
 /* Return a multiplier for brush strength on a particular vertex. */
-float tex_strength(EditData *e, float *point, const float len,const unsigned vindex)
+float tex_strength(BrushAction *a, float *point, const float len,const unsigned vindex)
 {
        SculptData *sd= sculpt_data();
        SculptSession *ss= sculpt_session();
@@ -747,12 +750,12 @@ float tex_strength(EditData *e, float *point, const float len,const unsigned vin
                /* If the active area is being applied for symmetry, flip it
                   across the symmetry axis in order to project it. This insures
                   that the brush texture will be oriented correctly. */
-               if(!e->symm)
+               if(!a->symm.index)
                        pv= ss->projverts[vindex];
                else {
                        float co[3];
                        VecCopyf(co, point);
-                       flip_coord(co, e->symm);
+                       flip_coord(co, a->symm.index);
                        project(co, pv.co);
                }
 
@@ -781,15 +784,15 @@ float tex_strength(EditData *e, float *point, const float len,const unsigned vin
                                py %= sy-1;
                        p= get_texcache_pixel(ss, tcw*px/sx, tch*py/sy);
                } else {
-                       float fx= (pv.co[0] - e->mouse[0] + half) * (tcw*1.0f/bsize) - tcw/2;
-                       float fy= (pv.co[1] - e->mouse[1] + half) * (tch*1.0f/bsize) - tch/2;
-                       
+                       float fx= (pv.co[0] - a->mouse[0] + half) * (tcw*1.0f/bsize) - tcw/2;
+                       float fy= (pv.co[1] - a->mouse[1] + half) * (tch*1.0f/bsize) - tch/2;
+
                        float angle= atan2(fy, fx) - rot;
                        float len= sqrtf(fx*fx + fy*fy);
                        
                        px= tcw/2 + len * cos(angle);
                        py= tch/2 + len * sin(angle);
-                       
+
                        p= get_texcache_pixel(ss, px, py);
                }
                
@@ -801,7 +804,7 @@ float tex_strength(EditData *e, float *point, const float len,const unsigned vin
        }
 
        if(sd->texfade)
-               avg*= curve_strength(len,e->size); /* Smooth curve */
+               avg*= curve_strength(len, a->size_3d); /* Smooth curve */
 
        return avg;
 }
@@ -809,7 +812,7 @@ float tex_strength(EditData *e, float *point, const float len,const unsigned vin
 /* Mark area around the brush as damaged. projverts are marked if they are
    inside the area and the damaged rectangle in 2D screen coordinates is 
    added to damaged_rects. */
-void sculpt_add_damaged_rect(EditData *e)
+void sculpt_add_damaged_rect(BrushAction *a)
 {
        short p[2];
        const float radius= brush_size();
@@ -819,7 +822,7 @@ void sculpt_add_damaged_rect(EditData *e)
        unsigned i;
 
        /* Find center */
-       project(&e->center.x, p);
+       project(a->symm.center_3d, p);
        rn->r.xmin= p[0]-radius;
        rn->r.ymin= p[1]-radius;
        rn->r.xmax= p[0]+radius;
@@ -868,7 +871,7 @@ void sculpt_clear_damaged_areas(SculptSession *ss)
        }
 }
 
-void do_brush_action(EditData e)
+void do_brush_action(BrushAction *a)
 {
        int i;
        float av_dist;
@@ -876,29 +879,32 @@ void do_brush_action(EditData e)
        ActiveData *adata= 0;
        float *vert;
        Mesh *me= get_mesh(OBACT);
-       const float bstrength= brush_strength(&e);
+       const float bstrength= brush_strength(a);
        KeyBlock *keyblock= ob_get_keyblock(OBACT);
+       SculptData *sd = sculpt_data();
        SculptSession *ss = sculpt_session();
 
-       sculpt_add_damaged_rect(&e);
+       sculpt_add_damaged_rect(a);
 
        /* Build a list of all vertices that are potentially within the brush's
           area of influence. Only do this once for the grab brush. */
-       if(!e.grabdata || (e.grabdata && e.grabdata->firsttime)) {
+       if((sd->brush_type != GRAB_BRUSH) || a->firsttime) {
                for(i=0; i<me->totvert; ++i) {
                        /* Projverts.inside provides a rough bounding box */
                        if(ss->projverts[i].inside) {
                                vert= ss->vertexcosnos ? &ss->vertexcosnos[i*6] : me->mvert[i].co;
-                               av_dist= VecLenf(&e.center.x,vert);
-                               if(av_dist < e.size) {
+                               av_dist= VecLenf(a->symm.center_3d, vert);
+                               if(av_dist < a->size_3d) {
                                        adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData");
+
                                        adata->Index = i;
                                        /* 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->Fade= tex_strength(a, 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);
+
+                                       if(sd->brush_type == GRAB_BRUSH && a->firsttime)
+                                               BLI_addtail(&a->grab_active_verts[a->symm.index], adata);
                                        else
                                                BLI_addtail(&active_verts, adata);
                                }
@@ -907,29 +913,29 @@ void do_brush_action(EditData e)
        }
 
        /* Only act if some verts are inside the brush area */
-       if(active_verts.first || (e.grabdata && e.grabdata->active_verts[e.grabdata->index].first)) {
+       if(active_verts.first || (sd->brush_type == GRAB_BRUSH && a->grab_active_verts[a->symm.index].first)) {
                /* Apply one type of brush action */
                switch(G.scene->sculptdata.brush_type){
                case DRAW_BRUSH:
-                       do_draw_brush(&e, &active_verts);
+                       do_draw_brush(a, &active_verts);
                        break;
                case SMOOTH_BRUSH:
-                       do_smooth_brush(&e, &active_verts);
+                       do_smooth_brush(a, &active_verts);
                        break;
                case PINCH_BRUSH:
-                       do_pinch_brush(&e, &active_verts);
+                       do_pinch_brush(a, &active_verts);
                        break;
                case INFLATE_BRUSH:
-                       do_inflate_brush(&e, &active_verts);
+                       do_inflate_brush(a, &active_verts);
                        break;
                case GRAB_BRUSH:
-                       do_grab_brush(&e);
+                       do_grab_brush(a);
                        break;
                case LAYER_BRUSH:
-                       do_layer_brush(&e, &active_verts);
+                       do_layer_brush(a, &active_verts);
                        break;
                case FLATTEN_BRUSH:
-                       do_flatten_brush(&e, &active_verts);
+                       do_flatten_brush(a, &active_verts);
                        break;
                }
        
@@ -937,7 +943,11 @@ void do_brush_action(EditData e)
                if(keyblock) {
                        float *co= keyblock->data;
                        if(co) {
-                               adata = e.grabdata ? e.grabdata->active_verts[e.grabdata->index].first : active_verts.first;
+                               if(sd->brush_type == GRAB_BRUSH)
+                                       adata = a->grab_active_verts[a->symm.index].first;
+                               else
+                                       adata = active_verts.first;
+
                                for(; adata; adata= adata->next)
                                        if(adata->Index < keyblock->totelem)
                                                VecCopyf(&co[adata->Index*3], me->mvert[adata->Index].co);
@@ -947,7 +957,7 @@ void do_brush_action(EditData e)
                if(ss->vertexcosnos)
                        BLI_freelistN(&active_verts);
                else {
-                       if(!e.grabdata)
+                       if(sd->brush_type != GRAB_BRUSH)
                                addlisttolist(&ss->damaged_verts, &active_verts);
                }
        }
@@ -955,51 +965,37 @@ void do_brush_action(EditData e)
 
 /* Flip all the editdata across the axis/axes specified by symm. Used to
    calculate multiple modifications to the mesh when symmetry is enabled. */
-EditData flip_editdata(EditData *e, const char symm)
+void calc_brushdata_symm(BrushAction *a, const char symm)
 {
-       EditData fe= *e;
-       GrabData *gd= fe.grabdata;
-       
-       flip_coord(&fe.center.x, symm);
-       flip_coord(&fe.up.x, symm);
-       flip_coord(&fe.right.x, symm);
-       flip_coord(&fe.out.x, symm);
+       flip_coord(a->symm.center_3d, symm);
+       flip_coord(a->symm.up, symm);
+       flip_coord(a->symm.right, symm);
+       flip_coord(a->symm.out, symm);
        
-       fe.symm= symm;
-
-       project(&e->center.x,fe.mouse);
-
-       if(gd) {
-               gd->index= symm;
-               gd->delta_symm= gd->delta;
-               flip_coord(&gd->delta_symm.x, symm);
-       }
+       a->symm.index= symm;
 
-       return fe;
+       flip_coord(a->symm.grab_delta, symm);
 }
 
-void do_symmetrical_brush_actions(EditData * e, short co[2], short pr_co[2])
+void do_symmetrical_brush_actions(BrushAction *a, short co[2], short pr_co[2])
 {
-       const char symm= sculpt_data()->symm;
+       const char symm = sculpt_data()->symm;
+       BrushActionSymm orig;
+       int i;
 
-       init_editdata(e, co, pr_co);
-       
-       do_brush_action(flip_editdata(e, 0));
+       init_brushaction(a, co, pr_co);
+       orig = a->symm;
+       do_brush_action(a);
        
-       if(symm & SYMM_X)
-               do_brush_action(flip_editdata(e, SYMM_X));
-       if(symm & SYMM_Y)
-               do_brush_action(flip_editdata(e, SYMM_Y));
-       if(symm & SYMM_Z)
-               do_brush_action(flip_editdata(e, SYMM_Z));
-       if(symm & SYMM_X && symm & SYMM_Y)
-               do_brush_action(flip_editdata(e, SYMM_X | SYMM_Y));
-       if(symm & SYMM_X && symm & SYMM_Z)
-               do_brush_action(flip_editdata(e, SYMM_X | SYMM_Z));
-       if(symm & SYMM_Y && symm & SYMM_Z)
-               do_brush_action(flip_editdata(e, SYMM_Y | SYMM_Z));
-       if(symm & SYMM_X && symm & SYMM_Y && symm & SYMM_Z)
-               do_brush_action(flip_editdata(e, SYMM_X | SYMM_Y | SYMM_Z));
+       for(i = 1; i <= symm; ++i) {
+               if(symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
+                       // Restore the original symmetry data
+                       a->symm = orig;
+
+                       calc_brushdata_symm(a, i);
+                       do_brush_action(a);
+               }
+       }
 }
 
 void add_face_normal(vec3f *norm, const MFace* face)
@@ -1039,19 +1035,17 @@ void update_damaged_vert(Mesh *me, ListBase *lb)
        }
 }
 
-void calc_damaged_verts(ListBase *damaged_verts, GrabData *grabdata)
+void calc_damaged_verts(ListBase *damaged_verts, BrushAction *a)
 {
        Mesh *me= get_mesh(OBACT);
+       int i;
+       
+       for(i=0; i<8; ++i)
+               update_damaged_vert(me, &a->grab_active_verts[i]);
 
-       if(grabdata) {
-               int i;
-               for(i=0; i<8; ++i)
-                       update_damaged_vert(me,&grabdata->active_verts[i]);
-       } else {
-               update_damaged_vert(me,damaged_verts);
-               BLI_freelistN(damaged_verts);
-               damaged_verts->first = damaged_verts->last = NULL;
-       }
+       update_damaged_vert(me, damaged_verts);
+       BLI_freelistN(damaged_verts);
+       damaged_verts->first = damaged_verts->last = NULL;
 }
 
 void projverts_clear_inside(SculptSession *ss)
@@ -1137,83 +1131,80 @@ void sculptmode_update_tex()
 }
 
 /* pr_mouse is only used for the grab brush, can be NULL otherwise */
-void init_editdata(EditData *e, short *mouse, short *pr_mouse)
+void init_brushaction(BrushAction *a, short *mouse, short *pr_mouse)
 {
        SculptData *sd = sculpt_data();
-       const float mouse_depth= get_depth(mouse[0],mouse[1]);
-       vec3f brush_edge_loc, zero_loc, oldloc;
+       const float mouse_depth = get_depth(mouse[0], mouse[1]);
+       float brush_edge_loc[3], zero_loc[3], oldloc[3];
        ModifierData *md;
        int i;
        const char flip = (get_qual() == LR_SHIFTKEY);
 
-       e->flip= flip;
+       a->flip = flip;
+       a->symm.index = 0;
+       a->mouse[0] = mouse[0];
+       a->mouse[1] = mouse[1];
        
        /* Convert the location and size of the brush to
           modelspace coords */
-       e->center= unproject(mouse[0],mouse[1],mouse_depth);
-       brush_edge_loc= unproject(mouse[0] +
-                                 brush_size(),mouse[1],
-                                 mouse_depth);
-       e->size= VecLenf(&e->center.x,&brush_edge_loc.x);
+       unproject(a->symm.center_3d, mouse[0], mouse[1], mouse_depth);
+       unproject(brush_edge_loc, mouse[0] + brush_size(), mouse[1], mouse_depth);
+       a->size_3d = VecLenf(a->symm.center_3d, brush_edge_loc);
 
        /* Set the pivot to allow the model to rotate around the center of the brush */
        if(get_depth(mouse[0],mouse[1]) < 1.0)
-               sculpt_session()->pivot= e->center;
+               VecCopyf(&sculpt_session()->pivot.x, a->symm.center_3d);
 
        /* Now project the Up, Right, and Out normals from view to model coords */
-       zero_loc= unproject(0, 0, 0);
-       e->up= unproject(0, -1, 0);
-       e->right= unproject(1, 0, 0);
-       e->out= unproject(0, 0, -1);
-       VecSubf(&e->up.x, &e->up.x, &zero_loc.x);
-       VecSubf(&e->right.x, &e->right.x, &zero_loc.x);
-       VecSubf(&e->out.x, &e->out.x, &zero_loc.x);
-       Normalize(&e->up.x);
-       Normalize(&e->right.x);
-       Normalize(&e->out.x);
+       unproject(zero_loc, 0, 0, 0);
+       unproject(a->symm.up, 0, -1, 0);
+       unproject(a->symm.right, 1, 0, 0);
+       unproject(a->symm.out, 0, 0, -1);
+       VecSubf(a->symm.up, a->symm.up, zero_loc);
+       VecSubf(a->symm.right, a->symm.right, zero_loc);
+       VecSubf(a->symm.out, a->symm.out, zero_loc);
+       Normalize(a->symm.up);
+       Normalize(a->symm.right);
+       Normalize(a->symm.out);
        
        /* Initialize mirror modifier clipping */
        for(i=0; i<3; ++i) {
-               e->clip[i]= 0;
-               e->cliptol[i]= 0;
+               a->clip[i]= 0;
+               a->cliptol[i]= 0;
        }
        for(md= OBACT->modifiers.first; md; md= md->next) {
                if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
                        const MirrorModifierData *mmd = (MirrorModifierData*) md;
                        
                        if(mmd->flag & MOD_MIR_CLIPPING) {
-                               e->clip[mmd->axis]= 1;
-                               if(mmd->tolerance > e->cliptol[mmd->axis])
-                                       e->cliptol[mmd->axis]= mmd->tolerance;
+                               a->clip[mmd->axis]= 1;
+                               if(mmd->tolerance > a->cliptol[mmd->axis])
+                                       a->cliptol[mmd->axis] = mmd->tolerance;
                        }
                }
        }
 
        if(sd->brush_type == GRAB_BRUSH) {
-               vec3f gcenter;
-               if(!e->grabdata) {
-                       e->grabdata= MEM_callocN(sizeof(GrabData),"grab data");
-                       e->grabdata->firsttime= 1;
-                       e->grabdata->depth= mouse_depth;
-               }
-               else
-                       e->grabdata->firsttime= 0;
-               
+               float gcenter[3];
+
+               if(a->firsttime) 
+                       a->depth = mouse_depth;
+
                /* Find the delta */
-               gcenter= unproject(mouse[0],mouse[1],e->grabdata->depth);
-               oldloc= unproject(pr_mouse[0],pr_mouse[1],e->grabdata->depth);
-               VecSubf(&e->grabdata->delta.x,&gcenter.x,&oldloc.x);
+               unproject(gcenter, mouse[0], mouse[1], a->depth);
+               unproject(oldloc, pr_mouse[0], pr_mouse[1], a->depth);
+               VecSubf(a->symm.grab_delta, gcenter, oldloc);
        }
        else if(sd->brush_type == LAYER_BRUSH) {
                Mesh *me= get_mesh(OBACT);
 
-               if(!e->layer_disps)
-                       e->layer_disps= MEM_callocN(sizeof(float)*me->totvert,"Layer disps");
-               if(!e->layer_store) {
+               if(!a->layer_disps)
+                       a->layer_disps= MEM_callocN(sizeof(float)*me->totvert,"Layer disps");
+               if(!a->layer_store) {
                        unsigned i;
-                       e->layer_store= MEM_mallocN(sizeof(vec3f)*me->totvert,"Layer store");
+                       a->layer_store= MEM_mallocN(sizeof(vec3f)*me->totvert,"Layer store");
                        for(i=0; i<me->totvert; ++i)
-                               VecCopyf(&e->layer_store[i].x,me->mvert[i].co);
+                               VecCopyf(&a->layer_store[i].x, me->mvert[i].co);
                }
        }
 }
@@ -1470,11 +1461,11 @@ void sculpt(void)
        /* lastSigMouse is for the rake, to store the last place the mouse movement was significant */
        short mouse[2], mvalo[2], lastSigMouse[2],firsttime=1, mousebut;
        short modifier_calculations= 0;
-       EditData e;
+       BrushAction *a = MEM_callocN(sizeof(BrushAction), "brush action");
        short spacing= 32000;
        int scissor_box[4];
        float offsetRot;
-       int smooth_stroke = 0;
+       int smooth_stroke = 0, i;
 
        if(!(G.f & G_SCULPTMODE) || G.obedit || !ob || ob->id.lib || !get_mesh(ob) || (get_mesh(ob)->totface == 0))
                return;
@@ -1541,14 +1532,13 @@ void sculpt(void)
                ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
        sculptmode_update_all_projverts(ss->vertexcosnos);
 
-       e.grabdata= NULL;
-       e.layer_disps= NULL;
-       e.layer_store= NULL;
+       a->layer_disps= NULL;
+       a->layer_store= NULL;
 
        /* Set scaling adjustment */
-       e.scale[0]= 1.0f / ob->size[0];
-       e.scale[1]= 1.0f / ob->size[1];
-       e.scale[2]= 1.0f / ob->size[2];
+       a->scale[0]= 1.0f / ob->size[0];
+       a->scale[1]= 1.0f / ob->size[1];
+       a->scale[2]= 1.0f / ob->size[2];
 
        /* Capture original copy */
        if(sd->flags & SCULPT_DRAW_FAST)
@@ -1571,6 +1561,7 @@ void sculpt(void)
                }
                
                if(firsttime || mouse[0]!=mvalo[0] || mouse[1]!=mvalo[1] || sculptmode_brush()->airbrush) {
+                       a->firsttime = firsttime;
                        firsttime= 0;
 
                        if(smooth_stroke)
@@ -1583,27 +1574,27 @@ void sculpt(void)
 
                        if(G.scene->sculptdata.brush_type != GRAB_BRUSH) {
                                if(smooth_stroke) {
-                                       sculpt_stroke_apply(&e);
+                                       sculpt_stroke_apply(a);
                                }
                                else if(sd->spacing==0 || spacing>sd->spacing) {
-                                       do_symmetrical_brush_actions(&e, mouse, NULL);
+                                       do_symmetrical_brush_actions(a, mouse, NULL);
                                        spacing= 0;
                                }
                        }
                        else {
-                               do_symmetrical_brush_actions(&e, mouse, mvalo);
-                               ss->pivot= unproject(mouse[0],mouse[1],e.grabdata->depth);
+                               do_symmetrical_brush_actions(a, mouse, mvalo);
+                               unproject(&ss->pivot.x, mouse[0], mouse[1], a->depth);
                        }
 
                        if(modifier_calculations || ob_get_keyblock(ob))
                                DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
 
                        if(modifier_calculations || sd->brush_type == GRAB_BRUSH || !(sd->flags & SCULPT_DRAW_FAST)) {
-                               calc_damaged_verts(&ss->damaged_verts,e.grabdata);
+                               calc_damaged_verts(&ss->damaged_verts, a);
                                scrarea_do_windraw(curarea);
                                screen_swapbuffers();
                        } else { /* Optimized drawing */
-                               calc_damaged_verts(&ss->damaged_verts,e.grabdata);
+                               calc_damaged_verts(&ss->damaged_verts, a);
 
                                /* Draw the stored image to the screen */
                                glAccum(GL_RETURN, 1);
@@ -1648,20 +1639,16 @@ void sculpt(void)
        set_tex_angle(offsetRot);
        
        if(smooth_stroke) {
-               sculpt_stroke_apply_all(&e);
-               calc_damaged_verts(&ss->damaged_verts,e.grabdata);
+               sculpt_stroke_apply_all(a);
+               calc_damaged_verts(&ss->damaged_verts, a);
                BLI_freelistN(&ss->damaged_rects);
        }
 
-       if(e.layer_disps) MEM_freeN(e.layer_disps);
-       if(e.layer_store) MEM_freeN(e.layer_store);
-       /* Free GrabData */
-       if(e.grabdata) {
-               int i;
-               for(i=0; i<8; ++i)
-                       BLI_freelistN(&e.grabdata->active_verts[i]);
-               MEM_freeN(e.grabdata);
-       }
+       if(a->layer_disps) MEM_freeN(a->layer_disps);
+       if(a->layer_store) MEM_freeN(a->layer_store);
+       for(i=0; i<8; ++i)
+               BLI_freelistN(&a->grab_active_verts[i]);
+       MEM_freeN(a);
        sculpt_stroke_free();
 
        sculpt_undo_push(G.scene->sculptdata.brush_type);
@@ -1728,7 +1715,7 @@ void set_sculptmode(void)
 static void sculptmode_do_pmv(Object *ob, rcti *hb_2d, int mode)
 {
        Mesh *me= get_mesh(ob);
-       vec3f hidebox[6];
+       float hidebox[6][3];
        vec3f plane_normals[4];
        float plane_ds[4];
        unsigned i, j;
@@ -1740,23 +1727,23 @@ static void sculptmode_do_pmv(Object *ob, rcti *hb_2d, int mode)
        const unsigned SHOW= 0, HIDE=1;
 
        /* Convert hide box from 2D to 3D */
-       hidebox[0]= unproject(hb_2d->xmin, hb_2d->ymax, 1);
-       hidebox[1]= unproject(hb_2d->xmax, hb_2d->ymax, 1);
-       hidebox[2]= unproject(hb_2d->xmax, hb_2d->ymin, 1);
-       hidebox[3]= unproject(hb_2d->xmin, hb_2d->ymin, 1);
-       hidebox[4]= unproject(hb_2d->xmin, hb_2d->ymax, 0);
-       hidebox[5]= unproject(hb_2d->xmax, hb_2d->ymin, 0);
+       unproject(hidebox[0], hb_2d->xmin, hb_2d->ymax, 1);
+       unproject(hidebox[1], hb_2d->xmax, hb_2d->ymax, 1);
+       unproject(hidebox[2], hb_2d->xmax, hb_2d->ymin, 1);
+       unproject(hidebox[3], hb_2d->xmin, hb_2d->ymin, 1);
+       unproject(hidebox[4], hb_2d->xmin, hb_2d->ymax, 0);
+       unproject(hidebox[5], hb_2d->xmax, hb_2d->ymin, 0);
        
        /* Calculate normals for each side of hide box */
-       CalcNormFloat(&hidebox[0].x,&hidebox[1].x,&hidebox[4].x,&plane_normals[0].x);
-       CalcNormFloat(&hidebox[1].x,&hidebox[2].x,&hidebox[5].x,&plane_normals[1].x);
-       CalcNormFloat(&hidebox[2].x,&hidebox[3].x,&hidebox[5].x,&plane_normals[2].x);
-       CalcNormFloat(&hidebox[3].x,&hidebox[0].x,&hidebox[4].x,&plane_normals[3].x);
+       CalcNormFloat(hidebox[0], hidebox[1], hidebox[4], &plane_normals[0].x);
+       CalcNormFloat(hidebox[1], hidebox[2], hidebox[5], &plane_normals[1].x);
+       CalcNormFloat(hidebox[2], hidebox[3], hidebox[5], &plane_normals[2].x);
+       CalcNormFloat(hidebox[3], hidebox[0], hidebox[4], &plane_normals[3].x);
        
        /* Calculate D for each side of hide box */
        for(i= 0; i<4; ++i)
-               plane_ds[i]= hidebox[i].x*plane_normals[i].x + hidebox[i].y*plane_normals[i].y +
-                       hidebox[i].z*plane_normals[i].z;
+               plane_ds[i]= hidebox[i][0]*plane_normals[i].x + hidebox[i][1]*plane_normals[i].y +
+                       hidebox[i][2]*plane_normals[i].z;
        
        /* Add partial visibility to mesh */
        if(!me->pv) {