Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorNicholas Bishop <nicholasbishop@gmail.com>2008-02-01 22:45:11 +0300
committerNicholas Bishop <nicholasbishop@gmail.com>2008-02-01 22:45:11 +0300
commit9d9ba570386a90285288daddcfcc5c399649585f (patch)
tree34d8dba4389e9eb1ec21e17c50a9d57e34db40ec /source
parent3e98fb0f389a66bd902a236e28702c6bd66b5442 (diff)
== Sculpt ==
Added a new brush option, "Anchored". When enabled, the brush doesn't move with the mouse, but rather stays in it's initial location and grows larger or smaller to follow the mouse. Good for brushing alphas on to the mesh. (Note that this option isn't available for the grab brush, and ignores the smooth stroke option.)
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/scene.c6
-rw-r--r--source/blender/makesdna/DNA_scene_types.h5
-rw-r--r--source/blender/src/buttons_editing.c4
-rw-r--r--source/blender/src/header_view3d.c4
-rw-r--r--source/blender/src/sculptmode.c220
-rw-r--r--source/blender/src/space.c2
6 files changed, 164 insertions, 77 deletions
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 23aca38463b..74b86415c63 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -604,9 +604,9 @@ void sculptdata_init(Scene *sce)
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.flag = sd->smoothbrush.flag =
+ sd->pinchbrush.flag = sd->inflatebrush.flag =
+ sd->layerbrush.flag = sd->flattenbrush.flag = 0;
sd->drawbrush.view= 0;
sd->brush_type= DRAW_BRUSH;
sd->texact= -1;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 7f2ea6cbeaa..29fc39e838f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -423,8 +423,8 @@ typedef struct BrushData
{
short size;
char strength, dir; /* Not used for smooth brush */
- char airbrush;
char view;
+ char flag;
char pad[2];
} BrushData;
@@ -707,6 +707,9 @@ typedef struct Scene {
#define FFMPEG_MULTIPLEX_AUDIO 1
#define FFMPEG_AUTOSPLIT_OUTPUT 2
+/* Sculpt brush flags */
+#define SCULPT_BRUSH_AIRBRUSH 1
+#define SCULPT_BRUSH_ANCHORED 2
/* SculptData.flags */
#define SCULPT_INPUT_SMOOTH 1
#define SCULPT_DRAW_FAST 2
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 59f51da965e..23463f9bb8d 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -5370,7 +5370,7 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned
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+178,cy,89,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move");
+ uiDefButBitC(block, TOG, SCULPT_BRUSH_AIRBRUSH, 0, "Airbrush", cx+178,cy,89,19, &sculptmode_brush()->flag,0,0,0,0, "Brush makes changes without waiting for the mouse to move");
cy-= 20;
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;
@@ -5419,6 +5419,8 @@ void sculptmode_draw_interface_brush(uiBlock *block, unsigned short cx, unsigned
cy-= 20;
if(sd->brush_type == DRAW_BRUSH)
uiDefButC(block,NUM,B_NOP, "View", cx,cy,80,19, &sculptmode_brush()->view, 0,10,20,0,"Pulls brush direction towards view");
+ cy-= 20;
+ uiDefButBitC(block, TOG, SCULPT_BRUSH_ANCHORED, 0, "Anchored", cx,cy,80,19, &sculptmode_brush()->flag, 0,0,0,0, "Keep the brush center anchored to the initial location");
uiBlockEndAlign(block);
/* Draw curve */
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index 5d35d44f9c1..c99e40c55bc 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -4533,7 +4533,7 @@ void do_view3d_sculptmenu(void *arg, int event)
BIF_undo_push("Brush type");
break;
case 7:
- br->airbrush= !br->airbrush;
+ br->flag ^= SCULPT_BRUSH_AIRBRUSH;
BIF_undo_push("Airbrush");
break;
case 8:
@@ -4632,7 +4632,7 @@ uiBlock *view3d_sculptmenu(void *arg_unused)
if(sd->brush_type!=GRAB_BRUSH) {
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, "");
+ uiDefIconTextBut(block, BUTM, 1, (br->flag & SCULPT_BRUSH_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 && 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, "");
diff --git a/source/blender/src/sculptmode.c b/source/blender/src/sculptmode.c
index 71e0a0398be..bd66ef9c2df 100644
--- a/source/blender/src/sculptmode.c
+++ b/source/blender/src/sculptmode.c
@@ -134,7 +134,7 @@ typedef struct BrushActionSymm {
float up[3], right[3], out[3];
- // Grab brush
+ /* Grab brush */
float grab_delta[3];
} BrushActionSymm;
@@ -143,17 +143,25 @@ typedef struct BrushAction {
char firsttime;
+ /* Some brushes need access to original mesh vertices */
+ vec3f *mesh_store;
+ short (*orig_norms)[3];
+
short mouse[2];
float size_3d;
+ float prev_radius;
+ float radius;
+
float *layer_disps;
- vec3f *layer_store;
char flip;
char clip[3];
float cliptol[3];
- // Grab brush
+ float anchored_rot;
+
+ /* Grab brush */
ListBase grab_active_verts[8];
float depth;
@@ -368,6 +376,7 @@ float brush_strength(BrushAction *a)
float pressure= 1;
short activedevice= get_activedevice();
float flip= a->flip ? -1:1;
+ float anchored = b->flag & SCULPT_BRUSH_ANCHORED ? 25 : 1;
const float strength_factor= G.scene->sculptdata.tablet_strength / 10.0f;
if(ELEM(activedevice, DEV_STYLUS, DEV_ERASER))
@@ -381,17 +390,17 @@ float brush_strength(BrushAction *a)
switch(G.scene->sculptdata.brush_type){
case DRAW_BRUSH:
case LAYER_BRUSH:
- return b->strength / 5000.0f * dir * pressure * flip;
+ return b->strength / 5000.0f * dir * pressure * flip * anchored;
case SMOOTH_BRUSH:
- return b->strength / 50.0f * pressure;
+ return b->strength / 50.0f * pressure * anchored;
case PINCH_BRUSH:
- return b->strength / 1000.0f * dir * pressure * flip;
+ return b->strength / 1000.0f * dir * pressure * flip * anchored;
case GRAB_BRUSH:
return 1;
case INFLATE_BRUSH:
- return b->strength / 5000.0f * dir * pressure * flip;
+ return b->strength / 5000.0f * dir * pressure * flip * anchored;
case FLATTEN_BRUSH:
- return b->strength / 500.0f * pressure;
+ return b->strength / 500.0f * pressure * anchored;
default:
return 0;
}
@@ -411,42 +420,54 @@ void sculpt_clip(const BrushAction *a, float *co, const float val[3])
/* Currently only for the draw brush; finds average normal for all active
vertices */
-vec3f calc_area_normal(const float *outdir, const ListBase* active_verts)
+void calc_area_normal(float out[3], const BrushAction *a, const float *outdir, const ListBase* active_verts)
{
- Mesh *me= get_mesh(OBACT);
- vec3f area_normal= {0,0,0};
- ActiveData *node= active_verts->first;
- const int view= sculpt_data()->brush_type==DRAW_BRUSH ? sculptmode_brush()->view : 0;
+ Mesh *me = get_mesh(OBACT);
+ ActiveData *node = active_verts->first;
+ const int view = sculpt_data()->brush_type==DRAW_BRUSH ? sculptmode_brush()->view : 0;
- while(node){
- area_normal.x+= me->mvert[node->Index].no[0];
- area_normal.y+= me->mvert[node->Index].no[1];
- area_normal.z+= me->mvert[node->Index].no[2];
- node= node->next;
+ out[0] = out[1] = out[2] = 0;
+
+ if(sculptmode_brush()->flag & SCULPT_BRUSH_ANCHORED) {
+ for(; node; node = node->next) {
+ out[0] += a->orig_norms[node->Index][0];
+ out[1] += a->orig_norms[node->Index][1];
+ out[2] += a->orig_norms[node->Index][2];
+ }
+ }
+ else {
+ for(; node; node = node->next) {
+ out[0] += me->mvert[node->Index].no[0];
+ out[1] += me->mvert[node->Index].no[1];
+ out[2] += me->mvert[node->Index].no[2];
+ }
}
- Normalize(&area_normal.x);
+
+ Normalize(out);
if(outdir) {
- 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);
+ out[0] = outdir[0] * view + out[0] * (10-view);
+ out[1] = outdir[1] * view + out[1] * (10-view);
+ out[2] = outdir[2] * view + out[2] * (10-view);
}
- Normalize(&area_normal.x);
- return area_normal;
+ Normalize(out);
}
+
void do_draw_brush(const BrushAction *a, const ListBase* active_verts)
{
Mesh *me= get_mesh(OBACT);
- const vec3f area_normal= calc_area_normal(a->symm.out, active_verts);
+ float area_normal[3];
ActiveData *node= active_verts->first;
+ calc_area_normal(area_normal, a, a->symm.out, active_verts);
+
while(node){
float *co= me->mvert[node->Index].co;
- 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]};
+ const float val[3]= {co[0]+area_normal[0]*node->Fade*a->scale[0],
+ co[1]+area_normal[1]*node->Fade*a->scale[1],
+ co[2]+area_normal[2]*node->Fade*a->scale[2]};
sculpt_clip(a, co, val);
@@ -556,10 +577,12 @@ void do_grab_brush(BrushAction *a)
void do_layer_brush(BrushAction *a, const ListBase *active_verts)
{
Mesh *me= get_mesh(OBACT);
- vec3f area_normal= calc_area_normal(NULL, active_verts);
+ float area_normal[3];
ActiveData *node= active_verts->first;
const float bstr= brush_strength(a);
+ calc_area_normal(area_normal, a, NULL, active_verts);
+
while(node){
float *disp= &a->layer_disps[node->Index];
@@ -578,9 +601,9 @@ void do_layer_brush(BrushAction *a, const ListBase *active_verts)
}
{
- 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]};
+ const float val[3]= {a->mesh_store[node->Index].x+area_normal[0] * *disp*a->scale[0],
+ a->mesh_store[node->Index].y+area_normal[1] * *disp*a->scale[1],
+ a->mesh_store[node->Index].z+area_normal[2] * *disp*a->scale[2]};
sculpt_clip(a, co, val);
}
}
@@ -642,9 +665,10 @@ 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(a->symm.out, active_verts);
+ float area_normal[3];
float cntr[3];
-
+
+ calc_area_normal(area_normal, a, a->symm.out, active_verts);
calc_flatten_center(me, node, cntr);
while(node){
@@ -652,11 +676,11 @@ void do_flatten_brush(const BrushAction *a, const ListBase *active_verts)
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(p1, co, area_normal);
VecSubf(sub1, cntr, p1);
VecSubf(sub2, co, p1);
VecSubf(intr, co, p1);
- VecMulf(intr, Inpf(&area_normal.x, sub1) / Inpf(&area_normal.x, sub2));
+ VecMulf(intr, Inpf(area_normal, sub1) / Inpf(area_normal, sub2));
VecAddf(intr, intr, p1);
VecSubf(val, intr, co);
@@ -778,8 +802,8 @@ float tex_strength(BrushAction *a, float *point, const float len,const unsigned
externtex(&mtex,point,&avg,&jnk,&jnk,&jnk,&jnk);
}
else if(ss->texcache) {
- const float bsize= sculptmode_brush()->size * 2;
- const float rot= to_rad(sculpt_tex_angle());
+ const float bsize= a->radius * 2;
+ const float rot= to_rad(sculpt_tex_angle()) + a->anchored_rot;
int px, py;
float flip[3], point_2d[2];
@@ -840,18 +864,18 @@ float tex_strength(BrushAction *a, float *point, const float len,const unsigned
void sculpt_add_damaged_rect(BrushAction *a)
{
short p[2];
- const float radius= brush_size();
RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode");
Mesh *me= get_mesh(OBACT);
SculptSession *ss = sculpt_session();
+ const float radius = a->radius > a->prev_radius ? a->radius : a->prev_radius;
unsigned i;
/* Find center */
project(a->symm.center_3d, p);
- rn->r.xmin= p[0]-radius;
- rn->r.ymin= p[1]-radius;
- rn->r.xmax= p[0]+radius;
- rn->r.ymax= p[1]+radius;
+ rn->r.xmin= p[0] - radius;
+ rn->r.ymin= p[1] - radius;
+ rn->r.xmax= p[0] + radius;
+ rn->r.ymax= p[1] + radius;
BLI_addtail(&sculpt_session()->damaged_rects, rn);
@@ -1011,7 +1035,7 @@ void do_symmetrical_brush_actions(BrushAction *a, short co[2], short pr_co[2])
init_brushaction(a, co, pr_co);
orig = a->symm;
do_brush_action(a);
-
+
for(i = 1; i <= symm; ++i) {
if(symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
// Restore the original symmetry data
@@ -1021,6 +1045,8 @@ void do_symmetrical_brush_actions(BrushAction *a, short co[2], short pr_co[2])
do_brush_action(a);
}
}
+
+ a->symm = orig;
}
void add_face_normal(vec3f *norm, const MFace* face)
@@ -1164,18 +1190,45 @@ void init_brushaction(BrushAction *a, short *mouse, short *pr_mouse)
ModifierData *md;
int i;
const char flip = (get_qual() == LR_SHIFTKEY);
+ const char anchored = sculptmode_brush()->flag & SCULPT_BRUSH_ANCHORED;
+ short orig_mouse[2], dx, dy;
a->flip = flip;
a->symm.index = 0;
- a->mouse[0] = mouse[0];
- a->mouse[1] = mouse[1];
+
+ if(a->firsttime)
+ a->depth = mouse_depth;
/* Convert the location and size of the brush to
modelspace coords */
- unproject(a->symm.center_3d, mouse[0], mouse[1], mouse_depth);
- unproject(brush_edge_loc, mouse[0] + brush_size(), mouse[1], mouse_depth);
+ if(a->firsttime || !anchored) {
+ unproject(a->symm.center_3d, mouse[0], mouse[1], mouse_depth);
+ a->mouse[0] = mouse[0];
+ a->mouse[1] = mouse[1];
+ }
+
+ if(anchored) {
+ project(a->symm.center_3d, orig_mouse);
+ dx = mouse[0] - orig_mouse[0];
+ dy = mouse[1] - orig_mouse[1];
+ }
+
+ if(anchored) {
+ unproject(brush_edge_loc, mouse[0], mouse[1], a->depth);
+ a->anchored_rot = atan2(dy, dx);
+ }
+ else
+ unproject(brush_edge_loc, mouse[0] + brush_size(), mouse[1], mouse_depth);
+
a->size_3d = VecLenf(a->symm.center_3d, brush_edge_loc);
+ a->prev_radius = a->radius;
+
+ if(anchored)
+ a->radius = sqrt(dx*dx + dy*dy);
+ else
+ a->radius = brush_size();
+
/* Set the pivot to allow the model to rotate around the center of the brush */
if(get_depth(mouse[0],mouse[1]) < 1.0)
VecCopyf(&sculpt_session()->pivot.x, a->symm.center_3d);
@@ -1212,9 +1265,6 @@ void init_brushaction(BrushAction *a, short *mouse, short *pr_mouse)
if(sd->brush_type == GRAB_BRUSH) {
float gcenter[3];
- if(a->firsttime)
- a->depth = mouse_depth;
-
/* Find the delta */
unproject(gcenter, mouse[0], mouse[1], a->depth);
unproject(oldloc, pr_mouse[0], pr_mouse[1], a->depth);
@@ -1225,13 +1275,27 @@ void init_brushaction(BrushAction *a, short *mouse, short *pr_mouse)
if(!a->layer_disps)
a->layer_disps= MEM_callocN(sizeof(float)*me->totvert,"Layer disps");
- if(!a->layer_store) {
- unsigned i;
- a->layer_store= MEM_mallocN(sizeof(vec3f)*me->totvert,"Layer store");
- for(i=0; i<me->totvert; ++i)
- VecCopyf(&a->layer_store[i].x, me->mvert[i].co);
- }
}
+
+ if(sd->brush_type == LAYER_BRUSH || anchored) {
+ Mesh *me= get_mesh(OBACT);
+ unsigned i;
+
+ if(!a->mesh_store) {
+ a->mesh_store= MEM_mallocN(sizeof(vec3f) * me->totvert, "Sculpt mesh store");
+ for(i = 0; i < me->totvert; ++i)
+ VecCopyf(&a->mesh_store[i].x, me->mvert[i].co);
+ }
+
+ if(anchored && !a->orig_norms) {
+ a->orig_norms= MEM_mallocN(sizeof(short) * 3 * me->totvert, "Sculpt orig norm");
+ for(i = 0; i < me->totvert; ++i) {
+ a->orig_norms[i][0] = me->mvert[i].no[0];
+ a->orig_norms[i][1] = me->mvert[i].no[1];
+ a->orig_norms[i][2] = me->mvert[i].no[2];
+ }
+ }
+ }
}
void sculptmode_set_strength(const int delta)
{
@@ -1491,6 +1555,7 @@ void sculpt(void)
int scissor_box[4];
float offsetRot;
int smooth_stroke = 0, i;
+ int anchored;
if(!(G.f & G_SCULPTMODE) || G.obedit || !ob || ob->id.lib || !get_mesh(ob) || (get_mesh(ob)->totface == 0))
return;
@@ -1508,7 +1573,8 @@ void sculpt(void)
ss= sd->session;
}
- smooth_stroke = (sd->flags & SCULPT_INPUT_SMOOTH) && (sd->brush_type != GRAB_BRUSH);
+ anchored = sculptmode_brush()->flag & SCULPT_BRUSH_ANCHORED;
+ smooth_stroke = (sd->flags & SCULPT_INPUT_SMOOTH) && (sd->brush_type != GRAB_BRUSH) && !anchored;
if(smooth_stroke)
sculpt_stroke_new(256);
@@ -1557,9 +1623,6 @@ void sculpt(void)
ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
sculptmode_update_all_projverts(ss->vertexcosnos);
- a->layer_disps= NULL;
- a->layer_store= NULL;
-
/* Set scaling adjustment */
a->scale[0]= 1.0f / ob->size[0];
a->scale[1]= 1.0f / ob->size[1];
@@ -1585,7 +1648,8 @@ void sculpt(void)
lastSigMouse[1]=mouse[1];
}
- if(firsttime || mouse[0]!=mvalo[0] || mouse[1]!=mvalo[1] || sculptmode_brush()->airbrush) {
+ if(firsttime || mouse[0]!=mvalo[0] || mouse[1]!=mvalo[1] ||
+ sculptmode_brush()->flag & SCULPT_BRUSH_AIRBRUSH) {
a->firsttime = firsttime;
firsttime= 0;
@@ -1598,12 +1662,29 @@ void sculpt(void)
ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
if(G.scene->sculptdata.brush_type != GRAB_BRUSH) {
- if(smooth_stroke) {
- sculpt_stroke_apply(a);
- }
- else if(sd->spacing==0 || spacing>sd->spacing) {
- do_symmetrical_brush_actions(a, mouse, NULL);
- spacing= 0;
+ if(anchored) {
+ Mesh *me = get_mesh(ob);
+
+ /* Restore the mesh before continuing with anchored stroke */
+ if(a->mesh_store) {
+ for(i = 0; i < me->totvert; ++i) {
+ VecCopyf(me->mvert[i].co, &a->mesh_store[i].x);
+ me->mvert[i].no[0] = a->orig_norms[i][0];
+ me->mvert[i].no[1] = a->orig_norms[i][1];
+ me->mvert[i].no[2] = a->orig_norms[i][2];
+ }
+ }
+
+ do_symmetrical_brush_actions(a, mouse, NULL);
+ }
+ else {
+ if(smooth_stroke) {
+ sculpt_stroke_apply(a);
+ }
+ else if(sd->spacing==0 || spacing>sd->spacing) {
+ do_symmetrical_brush_actions(a, mouse, NULL);
+ spacing= 0;
+ }
}
}
else {
@@ -1670,7 +1751,8 @@ void sculpt(void)
}
if(a->layer_disps) MEM_freeN(a->layer_disps);
- if(a->layer_store) MEM_freeN(a->layer_store);
+ if(a->mesh_store) MEM_freeN(a->mesh_store);
+ if(a->orig_norms) MEM_freeN(a->orig_norms);
for(i=0; i<8; ++i)
BLI_freelistN(&a->grab_active_verts[i]);
MEM_freeN(a);
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 950c3dec7e4..187cb1c9ef0 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -1446,7 +1446,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
break;
/* Brush properties */
case AKEY:
- br->airbrush= !br->airbrush;
+ br->flag ^= SCULPT_BRUSH_AIRBRUSH;
update_prop= 1; break;
case FKEY:
if(ss) {