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
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_paint.h1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c217
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h3
-rw-r--r--source/blender/editors/util/undo.c2
4 files changed, 189 insertions, 34 deletions
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 5bca174628d..ffb4e6ae743 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -70,6 +70,7 @@ typedef struct SculptSession {
int totvert, totface;
float *face_normals;
struct PBVH *tree;
+ struct Object *ob;
/* Mesh connectivity */
struct ListBase *fmap;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c8bfbec4e8b..0841fdfec22 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -37,6 +37,7 @@
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_pbvh.h"
+#include "BLI_threads.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
@@ -269,7 +270,133 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
BLI_pbvh_update(ob->sculpt->tree, PBVH_UpdateRedraw, NULL);
}
-/*** Looping Over Nodes in a BVH Node ***/
+/************************** Undo *************************/
+
+typedef struct SculptUndoNode {
+ struct SculptUndoNode *next, *prev;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ int maxvert; /* to verify if totvert it still the same */
+ void *node; /* only during push, not valid afterwards! */
+
+ float (*co)[3];
+ int *index;
+ int totvert;
+} SculptUndoNode;
+
+static void update_cb(PBVHNode *node, void *data)
+{
+ BLI_pbvh_node_mark_update(node);
+}
+
+static void sculpt_undo_restore(bContext *C, ListBase *lb)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ SculptUndoNode *unode;
+ MVert *mvert;
+ MultiresModifierData *mmd;
+ int *index;
+ int i, totvert, update= 0;
+
+ sculpt_update_mesh_elements(C, 0);
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(!(strcmp(unode->idname, ob->id.name)==0))
+ continue;
+ if(ss->totvert != unode->maxvert)
+ continue;
+
+ index= unode->index;
+ totvert= unode->totvert;
+ mvert= ss->mvert;
+
+ for(i=0; i<totvert; i++) {
+ float tmp[3];
+
+ VECCOPY(tmp, mvert[index[i]].co);
+ VECCOPY(mvert[index[i]].co, unode->co[i])
+ VECCOPY(unode->co[i], tmp);
+
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+
+ update= 1;
+ }
+
+ if(update) {
+ /* we update all nodes still, should be more clever, but also
+ needs to work correct when exiting/entering sculpt mode and
+ the nodes get recreated, though in that case it could do all */
+ BLI_pbvh_search_callback(ss->tree, NULL, NULL, update_cb, NULL);
+ BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL);
+
+ /* not really convinced this is correct .. */
+ if((mmd=sculpt_multires_active(ob))) {
+ mmd->undo_verts = ss->mvert;
+ mmd->undo_verts_tot = ss->totvert;
+ mmd->undo_signal = !!mmd->undo_verts;
+
+ multires_force_update(ob);
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ }
+ }
+}
+
+static void sculpt_undo_free(ListBase *lb)
+{
+ SculptUndoNode *unode;
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->co)
+ MEM_freeN(unode->co);
+ if(unode->index)
+ MEM_freeN(unode->index);
+ }
+}
+
+static float (*sculpt_undo_push_node(SculptSession *ss, PBVHNode *node))[3]
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ Object *ob= ss->ob;
+ SculptUndoNode *unode;
+ int i, totvert, *verts;
+
+ BLI_pbvh_node_get_verts(node, &verts, &totvert);
+
+ /* list is manipulated by multiple threads, so we lock */
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->node == node && strcmp(unode->idname, ob->id.name)==0) {
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return unode->co;
+ }
+ }
+
+ unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+ strcpy(unode->idname, ob->id.name);
+ unode->node= node;
+
+ unode->totvert= totvert;
+ unode->maxvert= ss->totvert;
+ /* we will use this while sculpting, is mapalloc slow to access then? */
+ unode->co= MEM_mapallocN(sizeof(float)*3*totvert, "SculptUndoNode.co");
+ unode->index= MEM_mapallocN(sizeof(int)*totvert, "SculptUndoNode.index");
+ undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(int))*totvert);
+ BLI_addtail(lb, unode);
+
+ BLI_unlock_thread(LOCK_CUSTOM1);
+
+ /* copy threaded, hopefully this is the performance critical part */
+ memcpy(unode->index, verts, sizeof(int)*totvert);
+ for(i=0; i<totvert; i++)
+ VECCOPY(unode->co[i], ss->mvert[verts[i]].co)
+
+ return unode->co;
+}
+
+/************************ Looping Over Verts in a BVH Node *******************/
typedef struct SculptVertexData {
float radius_squared;
@@ -277,38 +404,47 @@ typedef struct SculptVertexData {
MVert *mvert;
int *verts;
+ float (*origvert)[3];
int i, index, totvert;
float *co;
+ float *origco;
short *no;
float dist;
} SculptVertexData;
-static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss, PBVHNode *node, SculptVertexData *vd)
+static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss,
+ PBVHNode *node, float (*origvert)[3], SculptVertexData *vd)
{
vd->radius_squared= ss->cache->radius*ss->cache->radius;
VecCopyf(vd->location, ss->cache->location);
vd->mvert= ss->mvert;
- vd->i= 0;
+ vd->origvert= origvert;
+ vd->i= -1;
BLI_pbvh_node_get_verts(node, &vd->verts, &vd->totvert);
}
static int sculpt_node_verts_next(SculptVertexData *vd)
{
+ vd->i++;
+
while(vd->i < vd->totvert) {
float delta[3], dsq;
- vd->index= vd->verts[vd->i++];
+ vd->index= vd->verts[vd->i];
vd->co= vd->mvert[vd->index].co;
+ vd->origco= (vd->origvert)? vd->origvert[vd->i]: vd->co;
vd->no= vd->mvert[vd->index].no;
- VECSUB(delta, vd->co, vd->location);
+ VECSUB(delta, vd->origco, vd->location);
dsq = INPR(delta, delta);
if(dsq < vd->radius_squared) {
vd->dist = sqrt(dsq);
return 1;
}
+
+ vd->i++;
}
return 0;
@@ -563,7 +699,7 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3]
float nout[3] = {0.0f, 0.0f, 0.0f};
float nout_flip[3] = {0.0f, 0.0f, 0.0f};
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
if(brush->flag & BRUSH_ANCHORED) {
while(sculpt_node_verts_next(&vd))
@@ -614,7 +750,8 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
/* offset vertex */
@@ -686,7 +823,8 @@ static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
@@ -716,7 +854,8 @@ static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
@@ -774,7 +913,7 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
@@ -808,7 +947,8 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
@@ -846,7 +986,7 @@ static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
@@ -919,7 +1059,8 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **node
for(n=0; n<totnode; n++) {
SculptVertexData vd;
- sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
while(sculpt_node_verts_next(&vd)) {
float intr[3], val[3];
@@ -1155,7 +1296,7 @@ char sculpt_modifiers_active(Object *ob)
/* Sculpt mode handles multires differently from regular meshes, but only if
it's the last modifier on the stack and it is not on the first level */
-static struct MultiresModifierData *sculpt_multires_active(Object *ob)
+struct MultiresModifierData *sculpt_multires_active(Object *ob)
{
ModifierData *md, *nmd;
@@ -1177,14 +1318,14 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
return NULL;
}
-static void sculpt_update_mesh_elements(bContext *C)
+void sculpt_update_mesh_elements(bContext *C, int need_fmap)
{
Object *ob = CTX_data_active_object(C);
DerivedMesh *dm =
mesh_get_derived_final(CTX_data_scene(C), ob,
CTX_wm_view3d(C)->customdata_mask);
SculptSession *ss = ob->sculpt;
-
+
if((ss->multires = sculpt_multires_active(ob))) {
ss->totvert = dm->getNumVerts(dm);
ss->totface = dm->getNumFaces(dm);
@@ -1198,12 +1339,12 @@ static void sculpt_update_mesh_elements(bContext *C)
ss->totface = me->totface;
ss->mvert = me->mvert;
ss->mface = me->mface;
- if(!ss->face_normals)
- ss->face_normals = MEM_callocN(sizeof(float) * 3 * me->totface, "sculpt face normals");
+ ss->face_normals = NULL;
}
+ ss->ob = ob;
ss->tree = dm->getPBVH(dm);
- ss->fmap = dm->getFaceMap(dm);
+ ss->fmap = (need_fmap)? dm->getFaceMap(dm): NULL;
}
static int sculpt_mode_poll(bContext *C)
@@ -1217,27 +1358,27 @@ int sculpt_poll(bContext *C)
return sculpt_mode_poll(C) && paint_poll(C);
}
-static void sculpt_undo_push(bContext *C, Sculpt *sd)
+static char *sculpt_tool_name(Sculpt *sd)
{
Brush *brush = paint_brush(&sd->paint);
switch(brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- ED_undo_push(C, "Draw Brush"); break;
+ return "Draw Brush"; break;
case SCULPT_TOOL_SMOOTH:
- ED_undo_push(C, "Smooth Brush"); break;
+ return "Smooth Brush"; break;
case SCULPT_TOOL_PINCH:
- ED_undo_push(C, "Pinch Brush"); break;
+ return "Pinch Brush"; break;
case SCULPT_TOOL_INFLATE:
- ED_undo_push(C, "Inflate Brush"); break;
+ return "Inflate Brush"; break;
case SCULPT_TOOL_GRAB:
- ED_undo_push(C, "Grab Brush"); break;
+ return "Grab Brush"; break;
case SCULPT_TOOL_LAYER:
- ED_undo_push(C, "Layer Brush"); break;
+ return "Layer Brush"; break;
case SCULPT_TOOL_FLATTEN:
- ED_undo_push(C, "Flatten Brush"); break;
+ return "Flatten Brush"; break;
default:
- ED_undo_push(C, "Sculpting"); break;
+ return "Sculpting"; break;
}
}
@@ -1341,7 +1482,7 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
- sculpt_update_mesh_elements(C);
+ sculpt_update_mesh_elements(C, 0);
/* Initialize layer brush displacements */
if(brush->sculpt_tool == SCULPT_TOOL_LAYER &&
@@ -1589,7 +1730,7 @@ static void sculpt_brush_stroke_init(bContext *C)
changes are made to the texture. */
sculpt_update_tex(sd, ss);
- sculpt_update_mesh_elements(C);
+ sculpt_update_mesh_elements(C, 1);
}
static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
@@ -1661,11 +1802,17 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent
if(over_mesh) {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
sculpt_brush_stroke_init_properties(C, op, event, ss);
+ sculpt_update_cache_invariants(sd, ss, C, op);
+
+ undo_paint_push_begin(UNDO_PAINT_MESH, sculpt_tool_name(sd),
+ sculpt_undo_restore, sculpt_undo_free);
+
return 1;
}
else
@@ -1691,11 +1838,13 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
/* Finished */
if(ss->cache) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ // Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
sculpt_cache_free(ss->cache);
ss->cache = NULL;
- sculpt_undo_push(C, sd);
+
+ undo_paint_push_end(UNDO_PAINT_MESH);
+ // XXX ED_undo_push(C, sculpt_tool_name(sd));
}
}
@@ -1733,7 +1882,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
sculpt_flush_update(C);
sculpt_cache_free(ss->cache);
- sculpt_undo_push(C, sd);
+ // XXX ED_undo_push(C, sculpt_tool_name(sd));
return OPERATOR_FINISHED;
}
@@ -1809,7 +1958,7 @@ static void sculpt_init_session(bContext *C, Object *ob)
{
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- sculpt_update_mesh_elements(C);
+ sculpt_update_mesh_elements(C, 0);
}
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 15ccacc294a..d0eeacf5ea3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -40,6 +40,7 @@ struct Object;
struct Scene;
struct Sculpt;
struct SculptStroke;
+struct MultiresModifierData;
/* Interface */
void sculptmode_selectbrush_menu(void);
@@ -47,6 +48,7 @@ void sculptmode_draw_mesh(int);
void sculpt_paint_brush(char clear);
void sculpt_stroke_draw(struct SculptStroke *);
void sculpt_radialcontrol_start(int mode);
+struct MultiresModifierData *sculpt_multires_active(struct Object *ob);
struct Brush *sculptmode_brush(void);
//void do_symmetrical_brush_actions(struct Sculpt *sd, struct wmOperator *wm, struct BrushAction *a, short *, short *);
@@ -55,6 +57,7 @@ char sculpt_modifiers_active(struct Object *ob);
void sculpt(Sculpt *sd);
int sculpt_poll(struct bContext *C);
+void sculpt_update_mesh_elements(struct bContext *C, int need_fmap);
/* Stroke */
struct SculptStroke *sculpt_stroke_new(const int max);
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 18e3304c191..e20c88ba41f 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -147,6 +147,8 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
+ else if(obact && obact->mode & OB_MODE_SCULPT)
+ ED_undo_paint_step(C, UNDO_PAINT_MESH, step);
else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
if(step==1)
PE_undo(CTX_data_scene(C));