diff options
-rw-r--r-- | release/scripts/ui/space_view3d_toolbar.py | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/brush.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cdderivedmesh.c | 6 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_pbvh.h | 16 | ||||
-rw-r--r-- | source/blender/blenlib/intern/pbvh.c | 115 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_undo.c | 12 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 207 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 13 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 5 |
9 files changed, 262 insertions, 118 deletions
diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py index 0ad694efde1..7d1f905998a 100644 --- a/release/scripts/ui/space_view3d_toolbar.py +++ b/release/scripts/ui/space_view3d_toolbar.py @@ -523,6 +523,9 @@ class VIEW3D_PT_tools_brush(PaintPanel): if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'): col.row().itemR(brush, "direction", expand=True) + if brush.sculpt_tool in ('DRAW', 'INFLATE', 'LAYER'): + col.itemR(brush, "use_accumulate") + if brush.sculpt_tool == 'LAYER': col.itemR(brush, "use_persistent") col.itemO("sculpt.set_persistent_base") diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 8a4ffca8244..b415e7b7b17 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -75,13 +75,14 @@ Brush *add_brush(const char *name) brush->rgb[2]= 1.0f; brush->alpha= 0.2f; brush->size= 25; - brush->spacing= 10.0f; + brush->spacing= 7.5f; brush->smooth_stroke_radius= 75; brush->smooth_stroke_factor= 0.9; brush->rate= 0.1f; brush->jitter= 0.0f; brush->clone.alpha= 0.5; brush->sculpt_tool = SCULPT_TOOL_DRAW; + brush->flag |= BRUSH_SPACE; brush_curve_preset(brush, BRUSH_PRESET_SMOOTH); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 7cc46d39158..7acf77c6f90 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -420,11 +420,13 @@ static void draw_partial_cb(PBVHNode *node, void *data) Returns true if the AABB is at least partially within the frustum (ok, not a real frustum), false otherwise. */ -int planes_contain_AABB(PBVHNode *node, float bb_min[3], float bb_max[3], void *data) +int planes_contain_AABB(PBVHNode *node, void *data) { float (*planes)[4] = data; int i, axis; - float vmin[3], vmax[3]; + float vmin[3], vmax[3], bb_min[3], bb_max[3]; + + BLI_pbvh_node_get_BB(node, bb_min, bb_max); for(i = 0; i < 4; ++i) { for(axis = 0; axis < 3; ++axis) { diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h index ba9de462b3d..360a9937498 100644 --- a/source/blender/blenlib/BLI_pbvh.h +++ b/source/blender/blenlib/BLI_pbvh.h @@ -37,8 +37,7 @@ typedef struct PBVHNode PBVHNode; /* Callbacks */ /* returns 1 if the search should continue from this node, 0 otherwise */ -typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, - float bb_min[3], float bb_max[3], void *data); +typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data); typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data); @@ -69,7 +68,7 @@ void BLI_pbvh_search_gather(PBVH *bvh, hit first */ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data, - float ray_start[3], float ray_normal[3]); + float ray_start[3], float ray_normal[3], int original); /* Node Access */ @@ -78,20 +77,25 @@ typedef enum { PBVH_UpdateNormals = 2, PBVH_UpdateBB = 4, + PBVH_UpdateOriginalBB = 4, PBVH_UpdateDrawBuffers = 8, PBVH_UpdateRedraw = 16 } PBVHNodeFlags; void BLI_pbvh_node_mark_update(PBVHNode *node); -void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, int *totvert); -void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, int *totface); +void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, + int *totvert, int *allverts); +void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, + int **face_vert_indices, int *totface); void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node); +void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]); +void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]); /* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */ void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); -void BLI_pbvh_redraw_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3]); +void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); #endif /* BLI_PBVH_H */ diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c index 2a1f1484daa..4cf278d219e 100644 --- a/source/blender/blenlib/intern/pbvh.c +++ b/source/blender/blenlib/intern/pbvh.c @@ -82,12 +82,14 @@ struct PBVHNode { /* Voxel bounds */ BB vb; + BB orig_vb; /* For internal nodes */ int children_offset; /* Pointer into bvh face_indices */ int *face_indices; + int *face_vert_indices; unsigned short totface; unsigned short uniq_verts, face_verts; @@ -266,7 +268,7 @@ static void grow_nodes(PBVH *bvh, int totnode) /* Add a vertex to the map, with a positive value for unique vertices and a negative value for additional vertices */ -static void map_insert_vert(PBVH *bvh, GHash *map, +static int map_insert_vert(PBVH *bvh, GHash *map, unsigned short *face_verts, unsigned short *uniq_verts, int vertex) { @@ -284,7 +286,10 @@ static void map_insert_vert(PBVH *bvh, GHash *map, } BLI_ghash_insert(map, key, value); + return GET_INT_FROM_POINTER(value); } + else + return GET_INT_FROM_POINTER(BLI_ghash_lookup(map, key)); } /* Find vertices used by the faces in this node and update the draw buffers */ @@ -299,13 +304,17 @@ static void build_leaf_node(PBVH *bvh, PBVHNode *node) node->uniq_verts = node->face_verts = 0; totface= node->totface; + node->face_vert_indices = MEM_callocN(sizeof(int) * + 4*totface, "bvh node face vert indices"); + for(i = 0; i < totface; ++i) { MFace *f = bvh->faces + node->face_indices[i]; int sides = f->v4 ? 4 : 3; for(j = 0; j < sides; ++j) { - map_insert_vert(bvh, map, &node->face_verts, - &node->uniq_verts, (&f->v1)[j]); + node->face_vert_indices[i*4 + j]= + map_insert_vert(bvh, map, &node->face_verts, + &node->uniq_verts, (&f->v1)[j]); } } @@ -327,6 +336,10 @@ static void build_leaf_node(PBVH *bvh, PBVHNode *node) GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(iter)); } + for(i = 0; i < totface*4; ++i) + if(node->face_vert_indices[i] < 0) + node->face_vert_indices[i]= -node->face_vert_indices[i] + node->uniq_verts - 1; + node->draw_buffers = GPU_build_buffers(map, bvh->verts, bvh->faces, node->face_indices, @@ -370,6 +383,7 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, } build_leaf_node(bvh, bvh->nodes + node_index); + bvh->nodes[node_index].orig_vb= bvh->nodes[node_index].vb; /* Done with this subtree */ return; @@ -394,6 +408,8 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, (BB*)(prim_bbc + bvh->face_indices[i])); } + bvh->nodes[node_index].orig_vb= bvh->nodes[node_index].vb; + end = partition_indices(bvh->face_indices, offset, offset + count - 1, axis, (cb->bmax[axis] + cb->bmin[axis]) * 0.5f, @@ -480,6 +496,7 @@ void BLI_pbvh_free(PBVH *bvh) if(bvh->nodes[i].flag & PBVH_Leaf) { GPU_free_buffers(bvh->nodes[i].draw_buffers); MEM_freeN(bvh->nodes[i].vert_indices); + MEM_freeN(bvh->nodes[i].face_vert_indices); } } @@ -562,7 +579,7 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter) /* check search callback */ search_data= iter->search_data; - if(iter->scb && !iter->scb(node, node->vb.bmin, node->vb.bmax, search_data)) + if(iter->scb && !iter->scb(node, search_data)) continue; /* don't traverse, outside of search zone */ if(node->flag & PBVH_Leaf) { @@ -634,11 +651,12 @@ void BLI_pbvh_search_callback(PBVH *bvh, pbvh_iter_end(&iter); } -static int update_search_cb(PBVHNode *node, - float bb_min[3], float bb_max[3], void *data_v) +static int update_search_cb(PBVHNode *node, void *data_v) { + int flag= GET_INT_FROM_POINTER(data_v); + if(node->flag & PBVH_Leaf) - return (node->flag & (PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw)); + return (node->flag & flag); return 1; } @@ -670,7 +688,8 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, if((node->flag & PBVH_UpdateNormals)) { int i, j, totface, *faces; - BLI_pbvh_node_get_faces(node, &faces, &totface); + faces= node->face_indices; + totface= node->totface; for(i = 0; i < totface; ++i) { MFace *f= bvh->faces + faces[i]; @@ -713,7 +732,8 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, if(node->flag & PBVH_UpdateNormals) { int i, *verts, totvert; - BLI_pbvh_node_get_verts(node, &verts, &totvert); + verts= node->vert_indices; + totvert= node->uniq_verts; for(i = 0; i < totvert; ++i) { const int v = verts[i]; @@ -754,6 +774,9 @@ static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, /* don't clear flag yet, leave it for flushing later */ update_node_vb(bvh, node); + if((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB)) + node->orig_vb= node->vb; + if((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw)) node->flag &= ~PBVH_UpdateRedraw; } @@ -780,22 +803,32 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) } } -static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node) +static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) { int update= 0; /* difficult to multithread well, we just do single threaded recursive */ if(node->flag & PBVH_Leaf) { - update= (node->flag & PBVH_UpdateBB); - node->flag &= ~PBVH_UpdateBB; + if(flag & PBVH_UpdateBB) { + update |= (node->flag & PBVH_UpdateBB); + node->flag &= ~PBVH_UpdateBB; + } + + if(flag & PBVH_UpdateOriginalBB) { + update |= (node->flag & PBVH_UpdateOriginalBB); + node->flag &= ~PBVH_UpdateOriginalBB; + } + return update; } else { - update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset); - update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1); + update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset, flag); + update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1, flag); - if(update) + if(update & PBVH_UpdateBB) update_node_vb(bvh, node); + if(update & PBVH_UpdateOriginalBB) + node->orig_vb= node->vb; } return update; @@ -806,24 +839,25 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) PBVHNode **nodes; int totnode; - BLI_pbvh_search_gather(bvh, update_search_cb, NULL, &nodes, &totnode); + BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), + &nodes, &totnode); if(flag & PBVH_UpdateNormals) pbvh_update_normals(bvh, nodes, totnode, face_nors); - if(flag & (PBVH_UpdateBB|PBVH_UpdateRedraw)) + if(flag & (PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw)) pbvh_update_BB_redraw(bvh, nodes, totnode, flag); if(flag & PBVH_UpdateDrawBuffers) pbvh_update_draw_buffers(bvh, nodes, totnode); - if(flag & PBVH_UpdateBB) - pbvh_flush_bb(bvh, bvh->nodes); + if(flag & (PBVH_UpdateBB|PBVH_UpdateOriginalBB)) + pbvh_flush_bb(bvh, bvh->nodes, flag); if(nodes) MEM_freeN(nodes); } -void BLI_pbvh_redraw_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3]) +void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) { PBVHIter iter; PBVHNode *node; @@ -847,19 +881,21 @@ void BLI_pbvh_redraw_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3]) void BLI_pbvh_node_mark_update(PBVHNode *node) { - node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw; + node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw; } -void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, int *totvert) +void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, int *totvert, int *allvert) { - *vert_indices= node->vert_indices; - *totvert= node->uniq_verts; + if(vert_indices) *vert_indices= node->vert_indices; + if(totvert) *totvert= node->uniq_verts; + if(allvert) *allvert= node->uniq_verts + node->face_verts; } -void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, int *totface) +void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, int **face_vert_indices, int *totface) { - *face_indices= node->face_indices; - *totface= node->totface; + if(face_indices) *face_indices= node->face_indices; + if(face_vert_indices) *face_vert_indices= node->face_vert_indices; + if(totface) *totface= node->totface; } void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node) @@ -867,6 +903,18 @@ void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node) return node->draw_buffers; } +void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +{ + VecCopyf(bb_min, node->vb.bmin); + VecCopyf(bb_max, node->vb.bmax); +} + +void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +{ + VecCopyf(bb_min, node->orig_vb.bmin); + VecCopyf(bb_max, node->orig_vb.bmax); +} + /********************************* Raycast ***********************************/ typedef struct { @@ -874,15 +922,21 @@ typedef struct { float start[3]; int sign[3]; float inv_dir[3]; + int original; } RaycastData; /* Adapted from here: http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */ -static int ray_aabb_intersect(PBVHNode *node, float bb_min[3], float bb_max[3], void *data_v) +static int ray_aabb_intersect(PBVHNode *node, void *data_v) { RaycastData *ray = data_v; - float bbox[2][3]; + float bb_min[3], bb_max[3], bbox[2][3]; float tmin, tmax, tymin, tymax, tzmin, tzmax; + if(ray->original) + BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + else + BLI_pbvh_node_get_BB(node, bb_min, bb_max); + VecCopyf(bbox[0], bb_min); VecCopyf(bbox[1], bb_max); @@ -918,7 +972,7 @@ static int ray_aabb_intersect(PBVHNode *node, float bb_min[3], float bb_max[3], } void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data, - float ray_start[3], float ray_normal[3]) + float ray_start[3], float ray_normal[3], int original) { RaycastData rcd; @@ -929,6 +983,7 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data, rcd.sign[0] = rcd.inv_dir[0] < 0; rcd.sign[1] = rcd.inv_dir[1] < 0; rcd.sign[2] = rcd.inv_dir[2] < 0; + rcd.original = original; BLI_pbvh_search_callback(bvh, ray_aabb_intersect, &rcd, cb, data); } diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c index 9bc6cacbb16..05f2b565e82 100644 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ b/source/blender/editors/sculpt_paint/paint_undo.c @@ -191,10 +191,14 @@ void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFree ListBase *undo_paint_push_get_list(int type) { - if(type == UNDO_PAINT_IMAGE) - return &ImageUndoStack.current->elems; - else if(type == UNDO_PAINT_MESH) - return &MeshUndoStack.current->elems; + if(type == UNDO_PAINT_IMAGE) { + if(ImageUndoStack.current) + return &ImageUndoStack.current->elems; + } + else if(type == UNDO_PAINT_MESH) { + if(MeshUndoStack.current) + return &MeshUndoStack.current->elems; + } return NULL; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index fd614555fcb..d307b08385b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -108,15 +108,6 @@ * */ -/* ActiveData stores an Index into the mvert array of Mesh, plus Fade, which - stores how far the vertex is from the brush center, scaled to the range [0,1]. */ -typedef struct ActiveData { - struct ActiveData *next, *prev; - unsigned int Index; - float Fade; - float dist; -} ActiveData; - typedef enum StrokeFlags { CLIP_X = 1, CLIP_Y = 2, @@ -155,7 +146,6 @@ typedef struct StrokeCache { ViewContext *vc; Brush *brush; - 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 */ int pixel_radius, previous_pixel_radius; @@ -167,6 +157,7 @@ typedef struct StrokeCache { int symmetry; /* Symmetry index between 0 and 7 */ float view_normal[3], view_normal_symmetry[3]; int last_rake[2]; /* Last location of updating rake rotation */ + int original; } StrokeCache; /* ===== OPENGL ===== @@ -206,7 +197,7 @@ int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, view3d_get_object_project_mat(rv3d, ob, pmat); - BLI_pbvh_redraw_bounding_box(ob->sculpt->tree, bb_min, bb_max); + BLI_pbvh_redraw_BB(ob->sculpt->tree, bb_min, bb_max); rect->xmin = rect->ymin = INT_MAX; rect->xmax = rect->ymax = INT_MIN; @@ -280,6 +271,7 @@ typedef struct SculptUndoNode { void *node; /* only during push, not valid afterwards! */ float (*co)[3]; + short (*no)[3]; int *index; int totvert; } SculptUndoNode; @@ -329,7 +321,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) 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); + BLI_pbvh_update(ss->tree, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL); /* not really convinced this is correct .. */ if((mmd=sculpt_multires_active(ob))) { @@ -350,28 +342,43 @@ static void sculpt_undo_free(ListBase *lb) for(unode=lb->first; unode; unode=unode->next) { if(unode->co) MEM_freeN(unode->co); + if(unode->no) + MEM_freeN(unode->no); if(unode->index) MEM_freeN(unode->index); } } -static float (*sculpt_undo_push_node(SculptSession *ss, PBVHNode *node))[3] +static SculptUndoNode *sculpt_undo_get_node(SculptSession *ss, PBVHNode *node) +{ + ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH); + SculptUndoNode *unode; + + if(!lb) + return NULL; + + for(unode=lb->first; unode; unode=unode->next) + if(unode->node == node) + return unode; + + return NULL; +} + +static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node) { ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH); Object *ob= ss->ob; SculptUndoNode *unode; - int i, totvert, *verts; + int i, totvert, allvert, *verts; - BLI_pbvh_node_get_verts(node, &verts, &totvert); + BLI_pbvh_node_get_verts(node, &verts, &totvert, &allvert); /* 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; - } + if((unode= sculpt_undo_get_node(ss, node))) { + BLI_unlock_thread(LOCK_CUSTOM1); + return unode; } unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode"); @@ -381,19 +388,44 @@ static float (*sculpt_undo_push_node(SculptSession *ss, PBVHNode *node))[3] 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); + unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co"); + unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no"); + unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index"); + undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert); 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++) + memcpy(unode->index, verts, sizeof(int)*allvert); + for(i=0; i<allvert; i++) { VECCOPY(unode->co[i], ss->mvert[verts[i]].co) + VECCOPY(unode->no[i], ss->mvert[verts[i]].no) + } - return unode->co; + return unode; +} + +static void sculpt_undo_push_begin(SculptSession *ss, char *name) +{ + undo_paint_push_begin(UNDO_PAINT_MESH, name, + sculpt_undo_restore, sculpt_undo_free); +} + +static void sculpt_undo_push_end(SculptSession *ss) +{ + ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH); + SculptUndoNode *unode; + + /* we don't need normals in the undo stack */ + for(unode=lb->first; unode; unode=unode->next) { + if(unode->no) { + MEM_freeN(unode->no); + unode->no= NULL; + } + } + + undo_paint_push_end(UNDO_PAINT_MESH); } /************************ Looping Over Verts in a BVH Node *******************/ @@ -422,7 +454,7 @@ static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss, vd->mvert= ss->mvert; vd->origvert= origvert; vd->i= -1; - BLI_pbvh_node_get_verts(node, &vd->verts, &vd->totvert); + BLI_pbvh_node_get_verts(node, &vd->verts, &vd->totvert, NULL); } static int sculpt_node_verts_next(SculptVertexData *vd) @@ -628,14 +660,16 @@ typedef struct { } SculptSearchSphereData; /* Test AABB against sphere */ -static int sculpt_search_sphere_cb(PBVHNode *node, - float bb_min[3], float bb_max[3], void *data_v) +static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v) { SculptSearchSphereData *data = data_v; float *center = data->ss->cache->location, nearest[3]; - float t[3]; + float t[3], bb_min[3], bb_max[3]; int i; + //BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + BLI_pbvh_node_get_BB(node, bb_min, bb_max); + for(i = 0; i < 3; ++i) { if(bb_min[i] > center[i]) nearest[i] = bb_min[i]; @@ -682,7 +716,6 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons /* For draw/layer/flatten; finds average normal for all active vertices */ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3], PBVHNode **nodes, int totnode) { - Brush *brush = paint_brush(&sd->paint); StrokeCache *cache = ss->cache; const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */ float out[3] = {0.0f, 0.0f, 0.0f}; @@ -696,24 +729,30 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3] #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { SculptVertexData vd; + SculptUndoNode *unode; float nout[3] = {0.0f, 0.0f, 0.0f}; float nout_flip[3] = {0.0f, 0.0f, 0.0f}; + // XXX push instead of get for thread safety in draw + // brush .. lame, but also not harmful really + unode= sculpt_undo_push_node(ss, nodes[n]); sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); - if(brush->flag & BRUSH_ANCHORED) { + if(unode && ss->cache->original) { while(sculpt_node_verts_next(&vd)) - add_norm_if(out_dir, nout, nout_flip, cache->orig_norms[vd.index]); + add_norm_if(out_dir, nout, nout_flip, unode->no[vd.i]); } else { while(sculpt_node_verts_next(&vd)) add_norm_if(out_dir, nout, nout_flip, ss->mvert[vd.index].no); } - /* we sum per node and add together later for threads */ - #pragma omp critical - VecAddf(out, out, nout); - VecAddf(out_flip, out_flip, nout_flip); + { + /* we sum per node and add together later for threads */ + #pragma omp critical + VecAddf(out, out, nout); + VecAddf(out_flip, out_flip, nout_flip); + } } if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) { @@ -875,7 +914,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t { Brush *brush = paint_brush(&sd->paint); float bstrength= ss->cache->bstrength; - float grab_delta[3], (*origco)[3]; + float grab_delta[3]; int n; VecCopyf(grab_delta, ss->cache->grab_delta_symmetry); @@ -883,8 +922,11 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { SculptVertexData vd; + SculptUndoNode *unode; + float (*origco)[3]; - origco= sculpt_undo_push_node(ss, nodes[n]); + unode= sculpt_undo_push_node(ss, nodes[n]); + origco= unode->co; sculpt_node_verts_init(sd, ss, nodes[n], origco, &vd); while(sculpt_node_verts_next(&vd)) { @@ -921,9 +963,11 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { SculptVertexData vd; + SculptUndoNode *unode; float (*origco)[3]; - origco= sculpt_undo_push_node(ss, nodes[n]); + unode= sculpt_undo_push_node(ss, nodes[n]); + origco= unode->co; sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); while(sculpt_node_verts_next(&vd)) { @@ -1422,8 +1466,6 @@ static float unproject_brush_radius(ViewContext *vc, float center[3], float offs static void sculpt_cache_free(StrokeCache *cache) { int i; - if(cache->orig_norms) - MEM_freeN(cache->orig_norms); if(cache->face_norms) MEM_freeN(cache->face_norms); if(cache->mats) @@ -1479,21 +1521,20 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte /* Make copies of the mesh vertex locations and normals for some tools */ if(brush->flag & BRUSH_ANCHORED) { - cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * ss->totvert, "Sculpt orig norm"); - for(i = 0; i < ss->totvert; ++i) { - cache->orig_norms[i][0] = ss->mvert[i].no[0]; - cache->orig_norms[i][1] = ss->mvert[i].no[1]; - cache->orig_norms[i][2] = ss->mvert[i].no[2]; - } - if(ss->face_normals) { float *fn = ss->face_normals; cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms"); for(i = 0; i < ss->totface; ++i, fn += 3) VecCopyf(cache->face_norms[i], fn); } + + cache->original = 1; } + if(ELEM3(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE)) + if(!(brush->flag & BRUSH_ACCUMULATE)) + cache->original = 1; + cache->rotation = 0; cache->first_time = 1; } @@ -1601,15 +1642,47 @@ typedef struct { float *ray_start, *ray_normal; int hit; float dist; + int original; } SculptRaycastData; void sculpt_raycast_cb(PBVHNode *node, void *data_v) { SculptRaycastData *srd = data_v; MVert *vert = srd->ss->mvert; - int i, totface, *faces; + int i, totface, *faces, *face_verts; + + if(srd->original && srd->ss->cache) { + SculptUndoNode *unode; - BLI_pbvh_node_get_faces(node, &faces, &totface); + unode= sculpt_undo_get_node(srd->ss, node); + + if(unode) { + /* intersect with coordinates from before we started stroke */ + BLI_pbvh_node_get_faces(node, &faces, &face_verts, &totface); + + for(i = 0; i < totface; ++i) { + MFace *f = srd->ss->mface + faces[i]; + /*if(face_verts[i*4 + 0] >= unode->totvert) abort(); + if(face_verts[i*4 + 1] >= unode->totvert) abort(); + if(face_verts[i*4 + 2] >= unode->totvert) abort(); + if(f->v4 && face_verts[i*4 + 3] >= unode->totvert) abort();*/ + + if(ray_face_intersection(srd->ray_start, srd->ray_normal, + unode->co[face_verts[i*4+0]], + unode->co[face_verts[i*4+1]], + unode->co[face_verts[i*4+2]], + f->v4? unode->co[face_verts[i*4+3]]: NULL, + &srd->dist)) { + srd->hit = faces[i]; + } + } + + return; + } + } + + /* intersect with current coordinates */ + BLI_pbvh_node_get_faces(node, &faces, NULL, &totface); for(i = 0; i < totface; ++i) { MFace *f = srd->ss->mface + faces[i]; @@ -1631,6 +1704,8 @@ void sculpt_raycast_cb(PBVHNode *node, void *data_v) int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]) { ViewContext *vc = paint_stroke_view_context(stroke); + SculptSession *ss= vc->obact->sculpt; + StrokeCache *cache= ss->cache; float ray_start[3], ray_normal[3]; float mval[2] = {mouse[0] - vc->ar->winrct.xmin, mouse[1] - vc->ar->winrct.ymin}; @@ -1643,8 +1718,9 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou srd.ray_normal = ray_normal; srd.dist = FLT_MAX; srd.hit = -1; - BLI_pbvh_raycast(vc->obact->sculpt->tree, sculpt_raycast_cb, &srd, - ray_start, ray_normal); + srd.original = (cache)? cache->original: 0; + BLI_pbvh_raycast(ss->tree, sculpt_raycast_cb, &srd, + ray_start, ray_normal, srd.original); VecCopyf(out, ray_normal); VecMulf(out, srd.dist); @@ -1713,7 +1789,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) int i; /* Restore the mesh before continuing with anchored stroke */ - if((brush->flag & BRUSH_ANCHORED) && cache->orig_norms) { + if(brush->flag & BRUSH_ANCHORED) { ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH); SculptUndoNode *unode; @@ -1721,17 +1797,14 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) for(unode = lb->first; unode; unode = unode->next) { float (*co)[3]= unode->co; + short (*no)[3]= unode->no; int *index= unode->index; int totvert= unode->totvert; - for(i = 0; i < totvert; ++i) + for(i = 0; i < totvert; ++i) { VECCOPY(ss->mvert[index[i]].co, co[i]); - } - - for(i = 0; i < ss->totvert; ++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]; + VECCOPY(ss->mvert[index[i]].no, no[i]); + } } if(ss->face_normals) { @@ -1796,8 +1869,7 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent 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); + sculpt_undo_push_begin(ss, sculpt_tool_name(sd)); return 1; } @@ -1824,13 +1896,12 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) /* Finished */ if(ss->cache) { - // Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - sculpt_cache_free(ss->cache); ss->cache = NULL; - undo_paint_push_end(UNDO_PAINT_MESH); - // XXX ED_undo_push(C, sculpt_tool_name(sd)); + sculpt_undo_push_end(ss); + + BLI_pbvh_update(ss->tree, PBVH_UpdateOriginalBB, NULL); } } @@ -1868,8 +1939,6 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) sculpt_flush_update(C); sculpt_cache_free(ss->cache); - // XXX ED_undo_push(C, sculpt_tool_name(sd)); - return OPERATOR_FINISHED; } diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 1bbccd20486..c8fc14ca0f0 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -79,12 +79,13 @@ typedef struct Brush { #define BRUSH_JITTER_PRESSURE 16 /* was BRUSH_RAD_PRESSURE */ #define BRUSH_SPACING_PRESSURE 32 #define BRUSH_FIXED_TEX 64 -#define BRUSH_RAKE 128 -#define BRUSH_ANCHORED 256 -#define BRUSH_DIR_IN 512 -#define BRUSH_SPACE 1024 -#define BRUSH_SMOOTH_STROKE 2048 -#define BRUSH_PERSISTENT 4096 +#define BRUSH_RAKE 128 +#define BRUSH_ANCHORED 256 +#define BRUSH_DIR_IN 512 +#define BRUSH_SPACE 1024 +#define BRUSH_SMOOTH_STROKE 2048 +#define BRUSH_PERSISTENT 4096 +#define BRUSH_ACCUMULATE 8192 /* Brush.sculpt_tool */ #define SCULPT_TOOL_DRAW 1 diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index e9744c7f5ed..714526eb280 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -273,6 +273,11 @@ static void rna_def_brush(BlenderRNA *brna) 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."); RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop= RNA_def_property(srna, "use_accumulate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ACCUMULATE); + RNA_def_property_ui_text(prop, "Accumulate", "Accumulate stroke dabs on top of each other."); + RNA_def_property_update(prop, 0, "rna_Brush_update"); /* not exposed in the interface yet prop= RNA_def_property(srna, "fixed_tex", PROP_BOOLEAN, PROP_NONE); |