From c1ca2ab5dceb8d5355215a3c7a80b171f394e487 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 9 Aug 2009 17:21:40 +0000 Subject: Sculpt/2.5: * Added toolbar UI for setting "anchored" mode * Added a "persistent" mode for the layer brush; basically you can keep sculpting on the same layer between strokes when this is on. There's a button to reset the base so you can add another layer on top of that, and so on. This feature was suggested by Blenderer on BA, thanks! Note, I think these options could use better names in the UI, but I couldn't really think of anything very descriptive, suggestions welcome --- release/ui/space_view3d_toolbar.py | 7 +++ source/blender/blenkernel/BKE_sculpt.h | 4 ++ source/blender/blenkernel/intern/scene.c | 7 +++ source/blender/editors/sculpt_paint/sculpt.c | 73 +++++++++++++++++++++------- source/blender/makesdna/DNA_brush_types.h | 1 + source/blender/makesrna/intern/rna_brush.c | 4 ++ 6 files changed, 78 insertions(+), 18 deletions(-) diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index dd8a265947a..6edf57c7f58 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -369,8 +369,15 @@ class VIEW3D_PT_tools_brush(PaintPanel): col = layout.column() col.itemR(brush, "airbrush") + if brush.sculpt_tool != 'LAYER': + col.itemR(brush, "anchored") + if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'): col.itemR(brush, "flip_direction") + + if brush.sculpt_tool == 'LAYER': + col.itemR(brush, "persistent") + col.itemO("sculpt.set_persistent_base") # Texture Paint Mode # diff --git a/source/blender/blenkernel/BKE_sculpt.h b/source/blender/blenkernel/BKE_sculpt.h index 08db1ac632e..54cafc984a6 100644 --- a/source/blender/blenkernel/BKE_sculpt.h +++ b/source/blender/blenkernel/BKE_sculpt.h @@ -59,6 +59,10 @@ typedef struct SculptSession { /* Used to cache the render of the active texture */ unsigned int texcache_side, *texcache, texcache_actual; + /* Layer brush persistence between strokes */ + float (*mesh_co_orig)[3]; /* Copy of the mesh vertices' locations */ + float *layer_disps; /* Displacements for each vertex */ + void *cursor; /* wm handle */ struct SculptStroke *stroke; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d629654c426..a44118d186b 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -689,6 +689,13 @@ void sculptsession_free(Sculpt *sculpt) if(ss->texcache) MEM_freeN(ss->texcache); + + if(ss->layer_disps) + MEM_freeN(ss->layer_disps); + + if(ss->mesh_co_orig) + MEM_freeN(ss->mesh_co_orig); + MEM_freeN(ss); sculpt->session= NULL; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b1dcef39eee..94d3f39d172 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -145,8 +145,6 @@ typedef struct StrokeCache { ViewContext vc; bglMats *mats; - float *layer_disps; /* Displacements for each vertex */ - float (*mesh_store)[3]; /* Copy of the mesh vertices' locations */ short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */ float (*face_norms)[3]; /* Copy of the mesh faces' normals */ float rotation; /* Texture rotation (radians) for anchored and rake modes */ @@ -459,7 +457,7 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active calc_area_normal(sd, area_normal, active_verts); while(node){ - float *disp= &ss->cache->layer_disps[node->Index]; + float *disp= &ss->layer_disps[node->Index]; float *co= ss->mvert[node->Index].co; float val[3]; @@ -469,9 +467,9 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim)) *disp = lim; - val[0] = ss->cache->mesh_store[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0]; - val[1] = ss->cache->mesh_store[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1]; - val[2] = ss->cache->mesh_store[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2]; + val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0]; + val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1]; + val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2]; sculpt_clip(sd, co, val); @@ -1170,10 +1168,6 @@ static float unproject_brush_radius(SculptSession *ss, float offset) static void sculpt_cache_free(StrokeCache *cache) { - if(cache->layer_disps) - MEM_freeN(cache->layer_disps); - if(cache->mesh_store) - MEM_freeN(cache->mesh_store); if(cache->orig_norms) MEM_freeN(cache->orig_norms); if(cache->face_norms) @@ -1209,14 +1203,24 @@ static void sculpt_update_cache_invariants(Sculpt *sd, bContext *C, wmOperator * sculpt_update_mesh_elements(C); - if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER) - cache->layer_disps = MEM_callocN(sizeof(float) * sd->session->totvert, "layer brush displacements"); + /* Initialize layer brush displacements */ + if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER && + (!sd->session->layer_disps || !(sd->brush->flag & BRUSH_PERSISTENT))) { + if(sd->session->layer_disps) + MEM_freeN(sd->session->layer_disps); + sd->session->layer_disps = MEM_callocN(sizeof(float) * sd->session->totvert, "layer brush displacements"); + } /* Make copies of the mesh vertex locations and normals for some tools */ if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER || (sd->brush->flag & BRUSH_ANCHORED)) { - cache->mesh_store= MEM_mallocN(sizeof(float) * 3 * sd->session->totvert, "sculpt mesh vertices copy"); - for(i = 0; i < sd->session->totvert; ++i) - VecCopyf(cache->mesh_store[i], sd->session->mvert[i].co); + if(sd->brush->sculpt_tool != SCULPT_TOOL_LAYER || + !sd->session->mesh_co_orig || !(sd->brush->flag & BRUSH_PERSISTENT)) { + if(!sd->session->mesh_co_orig) + sd->session->mesh_co_orig= MEM_mallocN(sizeof(float) * 3 * sd->session->totvert, + "sculpt mesh vertices copy"); + for(i = 0; i < sd->session->totvert; ++i) + VecCopyf(sd->session->mesh_co_orig[i], sd->session->mvert[i].co); + } if(sd->brush->flag & BRUSH_ANCHORED) { cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * sd->session->totvert, "Sculpt orig norm"); @@ -1360,9 +1364,9 @@ static void sculpt_restore_mesh(Sculpt *sd) int i; /* Restore the mesh before continuing with anchored stroke */ - if((sd->brush->flag & BRUSH_ANCHORED) && cache->mesh_store) { + if((sd->brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) { for(i = 0; i < ss->totvert; ++i) { - VecCopyf(ss->mvert[i].co, cache->mesh_store[i]); + VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]); ss->mvert[i].no[0] = cache->orig_norms[i][0]; ss->mvert[i].no[1] = cache->orig_norms[i][1]; ss->mvert[i].no[2] = cache->orig_norms[i][2]; @@ -1375,7 +1379,7 @@ static void sculpt_restore_mesh(Sculpt *sd) } if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER) - memset(cache->layer_disps, 0, sizeof(float) * ss->totvert); + memset(ss->layer_disps, 0, sizeof(float) * ss->totvert); } } @@ -1610,6 +1614,38 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX); } +/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/ + +static int sculpt_set_persistent_base(bContext *C, wmOperator *op) +{ + SculptSession *ss = CTX_data_tool_settings(C)->sculpt->session; + + if(ss) { + if(ss->layer_disps) + MEM_freeN(ss->layer_disps); + ss->layer_disps = NULL; + + if(ss->mesh_co_orig) + MEM_freeN(ss->mesh_co_orig); + ss->mesh_co_orig = NULL; + } + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Set Persistent Base"; + ot->idname= "SCULPT_OT_set_persistent_base"; + + /* api callbacks */ + ot->exec= sculpt_set_persistent_base; + ot->poll= sculpt_mode_poll; + + ot->flag= OPTYPE_REGISTER; +} + /**** Toggle operator for turning sculpt mode on or off ****/ static int sculpt_toggle_mode(bContext *C, wmOperator *op) @@ -1670,4 +1706,5 @@ void ED_operatortypes_sculpt() WM_operatortype_append(SCULPT_OT_brush_stroke); WM_operatortype_append(SCULPT_OT_sculptmode_toggle); WM_operatortype_append(SCULPT_OT_brush_curve_preset); + WM_operatortype_append(SCULPT_OT_set_persistent_base); } diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index f88d3b68ebf..adb7fa2303d 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -85,6 +85,7 @@ typedef struct Brush { #define BRUSH_DIR_IN 512 #define BRUSH_SPACE 1024 #define BRUSH_SMOOTH_STROKE 2048 +#define BRUSH_PERSISTENT 4096 /* Brush.blend */ #define BRUSH_BLEND_MIX 0 diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 4dda4f12d96..1bc3987139f 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -220,6 +220,10 @@ void rna_def_brush(BlenderRNA *brna) prop= RNA_def_property(srna, "smooth_stroke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SMOOTH_STROKE); RNA_def_property_ui_text(prop, "Smooth Stroke", "Brush lags behind mouse and follows a smoother path."); + + prop= RNA_def_property(srna, "persistent", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PERSISTENT); + RNA_def_property_ui_text(prop, "Persistent", "Sculpts on a persistent layer of the mesh."); /* not exposed in the interface yet prop= RNA_def_property(srna, "fixed_tex", PROP_BOOLEAN, PROP_NONE); -- cgit v1.2.3