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--release/scripts/ui/space_view3d_toolbar.py3
-rw-r--r--source/blender/blenkernel/intern/brush.c3
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c6
-rw-r--r--source/blender/blenlib/BLI_pbvh.h16
-rw-r--r--source/blender/blenlib/intern/pbvh.c115
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c207
-rw-r--r--source/blender/makesdna/DNA_brush_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_brush.c5
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);