diff options
-rw-r--r-- | source/blender/blenkernel/BKE_key.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_paint.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cdderivedmesh.c | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/depsgraph.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/key.c | 149 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_pbvh.h | 6 | ||||
-rw-r--r-- | source/blender/blenlib/intern/pbvh.c | 65 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 138 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 2 |
9 files changed, 326 insertions, 57 deletions
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 6b8f18e9e17..c94955e611e 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -75,6 +75,8 @@ void key_to_latt(struct KeyBlock *kb, struct Lattice *lt); void latt_to_key(struct Lattice *lt, struct KeyBlock *kb); void key_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb); void curve_to_key(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb); +float (*key_to_vertcos(struct Object *ob, struct KeyBlock *kb))[3]; +void vertcos_to_key(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]); #ifdef __cplusplus }; diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 81fb724b3a5..cd412ca5a74 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -70,7 +70,7 @@ typedef struct SculptSession { int totvert, totface; float *face_normals; struct Object *ob; - struct KeyBlock *kb, *refkb; + struct KeyBlock *kb; /* Mesh connectivity */ struct ListBase *fmap; @@ -94,6 +94,8 @@ typedef struct SculptSession { struct StrokeCache *cache; struct GPUDrawObject *drawobject; + + int modifiers_active; } SculptSession; void free_sculptsession(struct Object *ob); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 80f39531b34..9612dac2ac4 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -186,6 +186,16 @@ static ListBase *cdDM_getFaceMap(Object *ob, DerivedMesh *dm) return cddm->fmap; } +static int can_pbvh_draw(Object *ob, DerivedMesh *dm) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) dm; + Mesh *me= (ob)? ob->data: NULL; + + if(ob->sculpt->modifiers_active) return 0; + + return (cddm->mvert == me->mvert) || ob->sculpt->kb; +} + static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) { CDDerivedMesh *cddm = (CDDerivedMesh*) dm; @@ -200,7 +210,7 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) return NULL; if(ob->sculpt->pbvh) { cddm->pbvh= ob->sculpt->pbvh; - cddm->pbvh_draw = (cddm->mvert == me->mvert) || ob->sculpt->kb; + cddm->pbvh_draw = can_pbvh_draw(ob, dm); } /* always build pbvh from original mesh, and only use it for drawing if @@ -208,7 +218,7 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) that this is actually for, to support a pbvh on a modified mesh */ if(!cddm->pbvh && ob->type == OB_MESH) { cddm->pbvh = BLI_pbvh_new(); - cddm->pbvh_draw = (cddm->mvert == me->mvert) || ob->sculpt->kb; + cddm->pbvh_draw = can_pbvh_draw(ob, dm); BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert, me->totface, me->totvert); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index bdeacdf6946..4be5cce38a8 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2286,9 +2286,6 @@ void DAG_id_flush_update(ID *id, short flag) /* no point in trying in this cases */ if(!id || id->us <= 1) id= NULL; - /* for locked shape keys we make an exception */ - else if(ob_get_key(ob) && (ob->shapeflag & OB_SHAPE_LOCK)) - id= NULL; } } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index f604d307551..84484417f42 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -38,6 +38,7 @@ #include "BLI_blenlib.h" #include "BLI_editVert.h" +#include "BLI_math_vector.h" #include "DNA_anim_types.h" #include "DNA_key_types.h" @@ -1719,3 +1720,151 @@ void key_to_mesh(KeyBlock *kb, Mesh *me) VECCOPY(mvert->co, fp); } } + +/************************* vert coords ************************/ +float (*key_to_vertcos(Object *ob, KeyBlock *kb))[3] +{ + float (*vertCos)[3], *co; + float *fp= kb->data; + int tot= 0, a; + + /* Count of vertex coords in array */ + if(ob->type == OB_MESH) { + Mesh *me= (Mesh*)ob->data; + tot= me->totvert; + } else if(ob->type == OB_LATTICE) { + Lattice *lt= (Lattice*)ob->data; + tot= lt->pntsu*lt->pntsv*lt->pntsw; + } else if(ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu= (Curve*)ob->data; + tot= count_curveverts(&cu->nurb); + } + + if (tot == 0) return NULL; + + vertCos= MEM_callocN(tot*sizeof(*vertCos), "key_to_vertcos vertCos"); + + /* Copy coords to array */ + co= (float*)vertCos; + + if(ELEM(ob->type, OB_MESH, OB_LATTICE)) { + for (a= 0; a<tot; a++, fp+=3, co+=3) { + copy_v3_v3(co, fp); + } + } else if(ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu= (Curve*)ob->data; + Nurb *nu= cu->nurb.first; + BezTriple *bezt; + BPoint *bp; + + while (nu) { + if(nu->bezt) { + int i; + bezt= nu->bezt; + a= nu->pntsu; + + while (a--) { + for (i= 0; i<3; i++) { + copy_v3_v3(co, fp); + fp+= 3; co+= 3; + } + + fp+= 3; /* skip alphas */ + + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + + while (a--) { + copy_v3_v3(co, fp); + + fp+= 4; + co+= 3; + + bp++; + } + } + + nu= nu->next; + } + } + + return vertCos; +} + +void vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) +{ + float *co= (float*)vertCos, *fp; + int tot= 0, a, elemsize; + + if (kb->data) MEM_freeN(kb->data); + + /* Count of vertex coords in array */ + if(ob->type == OB_MESH) { + Mesh *me= (Mesh*)ob->data; + tot= me->totvert; + elemsize= me->key->elemsize; + } else if(ob->type == OB_LATTICE) { + Lattice *lt= (Lattice*)ob->data; + tot= lt->pntsu*lt->pntsv*lt->pntsw; + elemsize= lt->key->elemsize; + } else if(ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu= (Curve*)ob->data; + elemsize= cu->key->elemsize; + tot= count_curveverts(&cu->nurb); + } + + fp= kb->data= MEM_callocN(tot*elemsize, "key_to_vertcos vertCos"); + + if (tot == 0) return; + + /* Copy coords to keyblock */ + + if(ELEM(ob->type, OB_MESH, OB_LATTICE)) { + for (a= 0; a<tot; a++, fp+=3, co+=3) { + copy_v3_v3(fp, co); + } + } else if(ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu= (Curve*)ob->data; + Nurb *nu= cu->nurb.first; + BezTriple *bezt; + BPoint *bp; + + while (nu) { + if(nu->bezt) { + int i; + bezt= nu->bezt; + a= nu->pntsu; + + while (a--) { + for (i= 0; i<3; i++) { + copy_v3_v3(fp, co); + fp+= 3; co+= 3; + } + + fp+= 3; /* skip alphas */ + + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + + while (a--) { + copy_v3_v3(fp, co); + + fp+= 4; + co+= 3; + + bp++; + } + } + + nu= nu->next; + } + } +} diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h index e32e85e70ec..519e3ddde1d 100644 --- a/source/blender/blenlib/BLI_pbvh.h +++ b/source/blender/blenlib/BLI_pbvh.h @@ -114,6 +114,12 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot void BLI_pbvh_grids_update(PBVH *bvh, struct DMGridData **grids, struct DMGridAdjacency *gridadj, void **gridfaces); +/* vertex deformer */ +float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3]; +void BLI_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); +int BLI_pbvh_isDeformed(struct PBVH *pbvh); + + /* Vertex Iterator */ /* this iterator has quite a lot of code, but it's designed to: diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c index 1fd18e2967c..92e2c88e8a1 100644 --- a/source/blender/blenlib/intern/pbvh.c +++ b/source/blender/blenlib/intern/pbvh.c @@ -29,6 +29,7 @@ #include "BLI_pbvh.h" #include "BKE_DerivedMesh.h" +#include "BKE_mesh.h" /* for mesh_calc_normals */ #include "gpu_buffers.h" @@ -120,6 +121,9 @@ struct PBVH { #ifdef PERFCNTRS int perf_modified; #endif + + /* flag are verts/faces deformed */ + int deformed; }; #define STACK_FIXED_DEPTH 100 @@ -576,6 +580,15 @@ void BLI_pbvh_free(PBVH *bvh) } } + if (bvh->deformed) { + if (bvh->verts) { + /* if pbvh was deformed, new memory was allocated for verts/faces -- free it */ + + MEM_freeN(bvh->verts); + MEM_freeN(bvh->faces); + } + } + MEM_freeN(bvh->nodes); MEM_freeN(bvh->prim_indices); MEM_freeN(bvh); @@ -1330,3 +1343,55 @@ void BLI_pbvh_grids_update(PBVH *bvh, DMGridData **grids, DMGridAdjacency *grida bvh->gridfaces= gridfaces; } +float (*BLI_pbvh_get_vertCos(PBVH *pbvh))[3] +{ + int a; + float (*vertCos)[3]= NULL; + + if (pbvh->verts) { + float *co; + MVert *mvert= pbvh->verts; + + vertCos= MEM_callocN(3*pbvh->totvert*sizeof(float), "BLI_pbvh_get_vertCoords"); + co= (float*)vertCos; + + for (a= 0; a<pbvh->totvert; a++, mvert++, co+= 3) { + copy_v3_v3(co, mvert->co); + } + } + + return vertCos; +} + +void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) +{ + int a; + + if (!pbvh->deformed) { + if (pbvh->verts) { + /* if pbvh is not already deformed, verts/faces points to the */ + /* original data and applying new coords to this arrays would lead to */ + /* unneeded deformation -- duplicate verts/faces to avoid this */ + + pbvh->verts= MEM_dupallocN(pbvh->verts); + pbvh->faces= MEM_dupallocN(pbvh->faces); + + pbvh->deformed= 1; + } + } + + if (pbvh->verts) { + /* copy new verts coords */ + for (a= 0; a < pbvh->totvert; ++a) { + copy_v3_v3(pbvh->verts[a].co, vertCos[a]); + } + + /* coordinates are new -- normals should also be updated */ + mesh_calc_normals(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL); + } +} + +int BLI_pbvh_isDeformed(PBVH *pbvh) +{ + return pbvh->deformed; +} diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index cf760f345b5..91769c92efe 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -275,6 +275,9 @@ typedef struct SculptUndoNode { /* layer brush */ float *layer_disp; + + /* shape keys */ + char *shapeName[32]; /* keep size in sync with keyblock dna */ } SculptUndoNode; static void update_cb(PBVHNode *node, void *data) @@ -326,16 +329,53 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) continue; if(unode->maxvert) { + char *shapeName= (char*)unode->shapeName; + /* regular mesh restore */ if(ss->totvert != unode->maxvert) continue; + if (ss->kb && strcmp(ss->kb->name, shapeName)) { + /* shape key has been changed before calling undo operator */ + + Key *key= ob_get_key(ob); + KeyBlock *kb= key_get_named_keyblock(key, shapeName); + + if (kb) { + ob->shapenr= BLI_findindex(&key->block, kb) + 1; + ob->shapeflag|= OB_SHAPE_LOCK; + + sculpt_update_mesh_elements(scene, ob, 0); + WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob); + } else { + /* key has been removed -- skip this undo node */ + continue; + } + } + index= unode->index; mvert= ss->mvert; - for(i=0; i<unode->totvert; i++) { - swap_v3_v3(mvert[index[i]].co, unode->co[i]); - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + if (ss->kb) { + float (*vertCos)[3]; + vertCos= key_to_vertcos(ob, ss->kb); + + for(i=0; i<unode->totvert; i++) + swap_v3_v3(vertCos[index[i]], unode->co[i]); + + /* propagate new coords to keyblock */ + vertcos_to_key(ob, ss->kb, vertCos); + + /* pbvh uses it's own mvert array, so coords should be */ + /* propagated to pbvh here */ + BLI_pbvh_apply_vertCos(ss->pbvh, vertCos); + + MEM_freeN(vertCos); + } else { + for(i=0; i<unode->totvert; i++) { + swap_v3_v3(mvert[index[i]].co, unode->co[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + } } } else if(unode->maxgrid && dm->getGridData) { @@ -365,9 +405,6 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) } if(update) { - if(ss->kb) sculpt_mesh_to_key(ss->ob, ss->kb); - if(ss->refkb) sculpt_key_to_mesh(ss->refkb, ob); - /* 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 */ @@ -377,7 +414,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) if((mmd=sculpt_multires_active(scene, ob))) multires_mark_as_modified(ob); - if(sculpt_modifiers_active(scene, ob)) + if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1) DAG_id_flush_update(&ob->id, OB_RECALC_DATA); } } @@ -475,7 +512,11 @@ static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node) if(unode->grids) memcpy(unode->grids, grids, sizeof(int)*totgrid); - + + /* store active shape key */ + if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name)); + else unode->shapeName[0]= '\0'; + return unode; } @@ -1367,6 +1408,17 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **node } } +/* copy the modified vertices from bvh to the active key */ +static void sculpt_update_keyblock(SculptSession *ss) +{ + float (*vertCos)[3]= BLI_pbvh_get_vertCos(ss->pbvh); + + if (vertCos) { + vertcos_to_key(ss->ob, ss->kb, vertCos); + MEM_freeN(vertCos); + } +} + static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache) { SculptSearchSphereData data; @@ -1424,13 +1476,15 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache) do_flatten_clay_brush(sd, ss, nodes, totnode, 1); break; } - - /* copy the modified vertices from mesh to the active key */ - if(ss->kb) mesh_to_key(ss->ob->data, ss->kb); - + + /* optimization: we could avoid copying new coords to keyblock at each */ + /* stroke step if there are no modifiers due to pbvh is used for displaying */ + /* so to increase speed we'll copy new coords to keyblock when stroke is done */ + if(ss->kb && ss->modifiers_active) sculpt_update_keyblock(ss); + if(nodes) MEM_freeN(nodes); - } + } } /* Flip all the editdata across the axis/axes specified by symm. Used to @@ -1506,40 +1560,18 @@ struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) return NULL; } -void sculpt_key_to_mesh(KeyBlock *kb, Object *ob) -{ - Mesh *me= ob->data; - - key_to_mesh(kb, me); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); -} - -void sculpt_mesh_to_key(Object *ob, KeyBlock *kb) -{ - Mesh *me= ob->data; - - mesh_to_key(me, kb); -} - void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap) { - DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0); + DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); SculptSession *ss = ob->sculpt; MultiresModifierData *mmd= sculpt_multires_active(scene, ob); ss->ob= ob; - if((ob->shapeflag & OB_SHAPE_LOCK) && !mmd) { - ss->kb= ob_get_keyblock(ob); - ss->refkb= ob_get_reference_keyblock(ob); - } - else { - ss->kb= NULL; - ss->refkb= NULL; - } + ss->modifiers_active= sculpt_modifiers_active(scene, ob); - /* need to make PBVH with shape key coordinates */ - if(ss->kb) sculpt_key_to_mesh(ss->kb, ss->ob); + if((ob->shapeflag & OB_SHAPE_LOCK) && !mmd) ss->kb= ob_get_keyblock(ob); + else ss->kb= NULL; if(mmd) { ss->multires = mmd; @@ -1561,6 +1593,17 @@ void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap) ss->pbvh = dm->getPBVH(ob, dm); ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(ob, dm): NULL; + + /* if pbvh is deformed, key block is already applied to it */ + if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) { + float (*vertCos)[3]= key_to_vertcos(ob, ss->kb); + + if (vertCos) { + /* apply shape keys coordinates to PBVH */ + BLI_pbvh_apply_vertCos(ss->pbvh, vertCos); + MEM_freeN(vertCos); + } + } } static int sculpt_mode_poll(bContext *C) @@ -1815,9 +1858,7 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct P static void sculpt_stroke_modifiers_check(bContext *C, SculptSession *ss) { - Scene *scene= CTX_data_scene(C); - - if(sculpt_modifiers_active(scene, ss->ob)) { + if(ss->modifiers_active) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Brush *brush = paint_brush(&sd->paint); @@ -1995,7 +2036,6 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) static void sculpt_flush_update(bContext *C) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; ARegion *ar = CTX_wm_region(C); @@ -2005,7 +2045,7 @@ static void sculpt_flush_update(bContext *C) if(mmd) multires_mark_as_modified(ob); - if(sculpt_modifiers_active(scene, ob)) { + if(ss->modifiers_active) { DAG_id_flush_update(&ob->id, OB_RECALC_DATA); ED_region_tag_redraw(ar); } @@ -2089,10 +2129,13 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL); - if(ss->refkb) sculpt_key_to_mesh(ss->refkb, ob); + /* optimization: if there is locked key and active modifiers present in */ + /* the stack, keyblock is updating at each step. otherwise we could update */ + /* keyblock only when stroke is finished */ + if(ss->kb && !ss->modifiers_active) sculpt_update_keyblock(ss); ss->partial_redraw = 0; - + /* try to avoid calling this, only for e.g. linked duplicates now */ if(((Mesh*)ob->data)->id.us > 1) DAG_id_flush_update(&ob->id, OB_RECALC_DATA); @@ -2225,9 +2268,6 @@ static void sculpt_init_session(Scene *scene, Object *ob) ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); sculpt_update_mesh_elements(scene, ob, 0); - - if(ob->sculpt->refkb) - sculpt_key_to_mesh(ob->sculpt->refkb, ob); } 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 d8043d2c988..c7c6833b695 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -58,8 +58,6 @@ void sculpt(Sculpt *sd); int sculpt_poll(struct bContext *C); void sculpt_update_mesh_elements(struct Scene *scene, struct Object *ob, int need_fmap); -void sculpt_key_to_mesh(struct KeyBlock *kb, struct Object *ob); -void sculpt_mesh_to_key(struct Object *ob, struct KeyBlock *kb); /* Stroke */ struct SculptStroke *sculpt_stroke_new(const int max); |