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:
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c58
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1365
4 files changed, 779 insertions, 652 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b5748d7bc88..0689e8e63d7 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -43,11 +43,13 @@ struct ARegion;
struct VPaint;
/* paint_stroke.c */
+typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr);
typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(struct bContext *C, StrokeTestStart test_start,
+struct PaintStroke *paint_stroke_new(struct bContext *C,
+ StrokeGetLocation get_location, StrokeTestStart test_start,
StrokeUpdateStep update_step, StrokeDone done);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 6e256bee7f2..c2d22089442 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -73,6 +73,7 @@ typedef struct PaintStroke {
passes over the mesh */
int stroke_started;
+ StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
StrokeDone done;
@@ -118,12 +119,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
{
PointerRNA itemptr;
- float cur_depth, pressure = 1;
- float center[3];
+ float pressure = 1;
+ float center[3] = {0, 0, 0};
PaintStroke *stroke = op->customdata;
- cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]);
- view3d_unproject(&stroke->mats, center, mouse[0], mouse[1], cur_depth);
+ /* XXX: can remove the if statement once all modes have this */
+ if(stroke->get_location)
+ stroke->get_location(C, stroke, center, mouse);
/* Tablet */
if(event->custom == EVT_DATA_TABLET) {
@@ -208,15 +210,19 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
/**** Public API ****/
-PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
- StrokeUpdateStep update_step, StrokeDone done)
+PaintStroke *paint_stroke_new(bContext *C,
+ StrokeGetLocation get_location,
+ StrokeTestStart test_start,
+ StrokeUpdateStep update_step,
+ StrokeDone done)
{
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C)));
view3d_set_viewcontext(C, &stroke->vc);
- view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats);
+ view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
+ stroke->get_location = get_location;
stroke->test_start = test_start;
stroke->update_step = update_step;
stroke->done = done;
@@ -226,12 +232,9 @@ PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
{
- ARegion *ar = CTX_wm_region(C);
PaintStroke *stroke = op->customdata;
float mouse[2];
-
- if(event->type == TIMER && (event->customdata != stroke->timer))
- return OPERATOR_RUNNING_MODAL;
+ int first= 0;
if(!stroke->stroke_started) {
stroke->last_mouse_position[0] = event->x;
@@ -246,26 +249,27 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
}
- ED_region_tag_redraw(ar);
+ first= 1;
+ //ED_region_tag_redraw(ar);
}
- if(stroke->stroke_started) {
- if(paint_smooth_stroke(stroke, mouse, event)) {
- if(paint_space_stroke_enabled(stroke->brush)) {
- if(!paint_space_stroke(C, op, event, mouse))
- ED_region_tag_redraw(ar);
+ /* TODO: fix hardcoded event here */
+ if(first || event->type == MOUSEMOVE || (event->type == TIMER && (event->customdata == stroke->timer))) {
+ if(stroke->stroke_started) {
+ if(paint_smooth_stroke(stroke, mouse, event)) {
+ if(paint_space_stroke_enabled(stroke->brush)) {
+ if(!paint_space_stroke(C, op, event, mouse))
+ ;//ED_region_tag_redraw(ar);
+ }
+ else
+ paint_brush_stroke_add_step(C, op, event, mouse);
}
else
- paint_brush_stroke_add_step(C, op, event, mouse);
+ ;//ED_region_tag_redraw(ar);
}
- else
- ED_region_tag_redraw(ar);
}
-
- /* TODO: fix hardcoded event here */
- if(event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- /* Exit stroke, free data */
-
+ else if(event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ /* exit stroke, free data */
if(stroke->smooth_stroke_cursor)
WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
@@ -276,8 +280,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
MEM_freeN(stroke);
return OPERATOR_FINISHED;
}
- else
- return OPERATOR_RUNNING_MODAL;
+
+ return OPERATOR_RUNNING_MODAL;
}
int paint_stroke_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 408f4862b6f..582a0c149b4 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1610,7 +1610,7 @@ static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- op->customdata = paint_stroke_new(C, wpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step,
wpaint_stroke_done);
@@ -1909,7 +1909,7 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- op->customdata = paint_stroke_new(C, vpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step,
vpaint_stroke_done);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c4c7f436f12..e29f0d56ba2 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -35,6 +35,8 @@
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
@@ -52,6 +54,7 @@
#include "DNA_color_types.h"
#include "BKE_brush.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
@@ -131,7 +134,6 @@ typedef struct StrokeCache {
int flag;
float clip_tolerance[3];
float initial_mouse[2];
- float depth;
/* Variants */
float radius;
@@ -140,6 +142,7 @@ typedef struct StrokeCache {
float flip;
float pressure;
float mouse[2];
+ float bstrength;
/* The rest is temporary storage that isn't saved as a property */
@@ -147,11 +150,17 @@ typedef struct StrokeCache {
bglMats *mats;
+ /* Clean this up! */
+ 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;
ListBase grab_active_verts[8]; /* The same list of verts is used throught grab stroke */
+ PBVHNode **grab_active_nodes[8];
+ int grab_active_totnode[8];
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3];
int symmetry; /* Symmetry index between 0 and 7 */
@@ -159,20 +168,6 @@ typedef struct StrokeCache {
int last_rake[2]; /* Last location of updating rake rotation */
} StrokeCache;
-typedef struct RectNode {
- struct RectNode *next, *prev;
- rcti r;
-} RectNode;
-
-/* Used to store to 2D screen coordinates of each vertex in the mesh. */
-typedef struct ProjVert {
- short co[2];
-
- /* Used to mark whether a vertex is inside a rough bounding box
- containing the brush. */
- char inside;
-} ProjVert;
-
/* ===== OPENGL =====
*
* Simple functions to get data from the GL
@@ -189,7 +184,7 @@ static void projectf(bglMats *mats, const float v[3], float p[2])
p[1]= uy;
}
-static void project(bglMats *mats, const float v[3], short p[2])
+/*XXX: static void project(bglMats *mats, const float v[3], short p[2])
{
float f[2];
projectf(mats, v, f);
@@ -197,6 +192,127 @@ static void project(bglMats *mats, const float v[3], short p[2])
p[0]= f[0];
p[1]= f[1];
}
+*/
+
+/*** BVH Tree ***/
+
+/* Get a screen-space rectangle of the modified area */
+int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
+ Object *ob, rcti *rect)
+{
+ float bb_min[3], bb_max[3], pmat[4][4];
+ int i, j, k;
+
+ view3d_get_object_project_mat(rv3d, ob, pmat);
+
+ BLI_pbvh_redraw_bounding_box(ob->sculpt->tree, bb_min, bb_max);
+
+ rect->xmin = rect->ymin = INT_MAX;
+ rect->xmax = rect->ymax = INT_MIN;
+
+ if(bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
+ return 0;
+
+ for(i = 0; i < 2; ++i) {
+ for(j = 0; j < 2; ++j) {
+ for(k = 0; k < 2; ++k) {
+ float vec[3], proj[2];
+ vec[0] = i ? bb_min[0] : bb_max[0];
+ vec[1] = j ? bb_min[1] : bb_max[1];
+ vec[2] = k ? bb_min[2] : bb_max[2];
+ view3d_project_float(ar, vec, proj, pmat);
+ rect->xmin = MIN2(rect->xmin, proj[0]);
+ rect->xmax = MAX2(rect->xmax, proj[0]);
+ rect->ymin = MIN2(rect->ymin, proj[1]);
+ rect->ymax = MAX2(rect->ymax, proj[1]);
+ }
+ }
+ }
+
+ return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
+}
+
+void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
+ RegionView3D *rv3d, Object *ob)
+{
+ BoundBox *bb = MEM_callocN(sizeof(BoundBox), "sculpt boundbox");
+ bglMats mats;
+ int i;
+ rcti rect;
+
+ view3d_get_transformation(ar, rv3d, ob, &mats);
+ sculpt_get_redraw_rect(ar, rv3d,ob, &rect);
+
+#if 1
+ /* use some extra space just in case */
+ rect.xmin -= 2;
+ rect.xmax += 2;
+ rect.ymin -= 2;
+ rect.ymax += 2;
+#else
+ /* it was doing this before, allows to redraw a smaller
+ part of the screen but also gives artifaces .. */
+ rect.xmin += 2;
+ rect.xmax -= 2;
+ rect.ymin += 2;
+ rect.ymax -= 2;
+#endif
+
+ view3d_calculate_clipping(bb, planes, &mats, &rect);
+
+ for(i = 0; i < 16; ++i)
+ ((float*)planes)[i] = -((float*)planes)[i];
+
+ MEM_freeN(bb);
+
+ /* clear redraw flag from nodes */
+ BLI_pbvh_update(ob->sculpt->tree, PBVH_UpdateRedraw, NULL, NULL);
+}
+
+/*** Looping Over Nodes in a BVH Node ***/
+
+typedef struct SculptVertexData {
+ float radius_squared;
+ float location[3];
+
+ MVert *mvert;
+ int *verts;
+ int i, index, totvert;
+
+ float *co;
+ short *no;
+ float dist;
+} SculptVertexData;
+
+static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss, PBVHNode *node, SculptVertexData *vd)
+{
+ vd->radius_squared= ss->cache->radius*ss->cache->radius;
+ VecCopyf(vd->location, ss->cache->location);
+
+ vd->mvert= ss->mvert;
+ vd->i= 0;
+ BLI_pbvh_node_get_verts(node, &vd->verts, &vd->totvert);
+}
+
+static int sculpt_node_verts_next(SculptVertexData *vd)
+{
+ while(vd->i < vd->totvert) {
+ float delta[3], dsq;
+
+ vd->index= vd->verts[vd->i++];
+ vd->co= vd->mvert[vd->index].co;
+ vd->no= vd->mvert[vd->index].no;
+ VECSUB(delta, vd->co, vd->location);
+ dsq = INPR(delta, delta);
+
+ if(dsq < vd->radius_squared) {
+ vd->dist = sqrt(dsq);
+ return 1;
+ }
+ }
+
+ return 0;
+}
/* ===== Sculpting =====
*
@@ -236,6 +352,168 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache)
}
}
+/* Uses symm to selectively flip any axis of a coordinate. */
+static void flip_coord(float out[3], float in[3], const char symm)
+{
+ if(symm & SCULPT_SYMM_X)
+ out[0]= -in[0];
+ else
+ out[0]= in[0];
+ if(symm & SCULPT_SYMM_Y)
+ out[1]= -in[1];
+ else
+ out[1]= in[1];
+ if(symm & SCULPT_SYMM_Z)
+ out[2]= -in[2];
+ else
+ out[2]= in[2];
+}
+
+/* Get a pixel from the texcache at (px, py) */
+static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
+{
+ unsigned *p;
+ p = ss->texcache + py * ss->texcache_side + px;
+ return ((unsigned char*)(p))[0];
+}
+
+static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
+{
+ int x, y, x2, y2;
+ const int tc_max = ss->texcache_side - 1;
+ float urat, vrat, uopp;
+
+ if(u < 0) u = 0;
+ else if(u >= ss->texcache_side) u = tc_max;
+ if(v < 0) v = 0;
+ else if(v >= ss->texcache_side) v = tc_max;
+
+ x = floor(u);
+ y = floor(v);
+ x2 = x + 1;
+ y2 = y + 1;
+
+ if(x2 > ss->texcache_side) x2 = tc_max;
+ if(y2 > ss->texcache_side) y2 = tc_max;
+
+ urat = u - x;
+ vrat = v - y;
+ uopp = 1 - urat;
+
+ return ((get_texcache_pixel(ss, x, y) * uopp +
+ get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) +
+ (get_texcache_pixel(ss, x, y2) * uopp +
+ get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
+}
+
+/* Return a multiplier for brush strength on a particular vertex. */
+static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
+{
+ MTex *tex = NULL;
+ float avg= 1;
+
+ if(br->texact >= 0)
+ tex = br->mtex[br->texact];
+
+ if(!tex) {
+ avg= 1;
+ }
+ else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ float jnk;
+
+ /* Get strength by feeding the vertex
+ location directly into a texture */
+ externtex(tex, point, &avg,
+ &jnk, &jnk, &jnk, &jnk);
+ }
+ else if(ss->texcache) {
+ const float bsize= ss->cache->pixel_radius * 2;
+ const float rot= tex->rot + ss->cache->rotation;
+ int px, py;
+ float flip[3], point_2d[2];
+
+ /* If the active area is being applied for symmetry, flip it
+ across the symmetry axis in order to project it. This insures
+ that the brush texture will be oriented correctly. */
+ VecCopyf(flip, point);
+ flip_coord(flip, flip, ss->cache->symmetry);
+ projectf(ss->cache->mats, flip, point_2d);
+
+ /* For Tile and Drag modes, get the 2D screen coordinates of the
+ and scale them up or down to the texture size. */
+ if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ const int sx= (const int)tex->size[0];
+ const int sy= (const int)tex->size[1];
+
+ float fx= point_2d[0];
+ float fy= point_2d[1];
+
+ float angle= atan2(fy, fx) - rot;
+ float flen= sqrtf(fx*fx + fy*fy);
+
+ if(rot<0.001 && rot>-0.001) {
+ px= point_2d[0];
+ py= point_2d[1];
+ } else {
+ px= flen * cos(angle) + 2000;
+ py= flen * sin(angle) + 2000;
+ }
+ if(sx != 1)
+ px %= sx-1;
+ if(sy != 1)
+ py %= sy-1;
+ avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
+ }
+ else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize;
+ float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize;
+
+ float angle= atan2(fy, fx) - rot;
+ float flen= sqrtf(fx*fx + fy*fy);
+
+ fx = flen * cos(angle) + 0.5;
+ fy = flen * sin(angle) + 0.5;
+
+ avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
+ }
+ }
+
+ avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
+
+ return avg;
+}
+
+typedef struct {
+ Sculpt *sd;
+ SculptSession *ss;
+ float radius_squared;
+ ListBase *active_verts;
+ float area_normal[3];
+} SculptSearchSphereData;
+
+/* Test AABB against sphere */
+static int sculpt_search_sphere_cb(PBVHNode *node,
+ float bb_min[3], float bb_max[3], void *data_v)
+{
+ SculptSearchSphereData *data = data_v;
+ float *center = data->ss->cache->location, nearest[3];
+ float t[3];
+ int i;
+
+ for(i = 0; i < 3; ++i) {
+ if(bb_min[i] > center[i])
+ nearest[i] = bb_min[i];
+ else if(bb_max[i] < center[i])
+ nearest[i] = bb_max[i];
+ else
+ nearest[i] = center[i];
+ }
+
+ VecSubf(t, center, nearest);
+
+ return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
+}
+
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float val[3])
{
@@ -265,26 +543,41 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons
}
}
-/* Currently only for the draw brush; finds average normal for all active
- vertices */
-static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const ListBase* active_verts)
+/* 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;
- ActiveData *node = active_verts->first;
const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
- float out_flip[3];
- float *out_dir = cache->view_normal_symmetry;
-
- out[0]=out[1]=out[2] = out_flip[0]=out_flip[1]=out_flip[2] = 0;
+ float out[3] = {0.0f, 0.0f, 0.0f};
+ float out_flip[3] = {0.0f, 0.0f, 0.0f};
+ float out_dir[3];
+ int n;
+
+ VecCopyf(out_dir, cache->view_normal_symmetry);
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
+ 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);
- if(brush->flag & BRUSH_ANCHORED) {
- for(; node; node = node->next)
- add_norm_if(out_dir, out, out_flip, cache->orig_norms[node->Index]);
- }
- else {
- for(; node; node = node->next)
- add_norm_if(out_dir, out, out_flip, ss->mvert[node->Index].no);
+ if(brush->flag & BRUSH_ANCHORED) {
+ while(sculpt_node_verts_next(&vd))
+ add_norm_if(out_dir, nout, nout_flip, cache->orig_norms[vd.index]);
+ }
+ 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);
}
if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) {
@@ -293,46 +586,48 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const
Normalize(out);
- if(out_dir) {
- out[0] = out_dir[0] * view + out[0] * (10-view);
- out[1] = out_dir[1] * view + out[1] * (10-view);
- out[2] = out_dir[2] * view + out[2] * (10-view);
- }
+ out[0] = out_dir[0] * view + out[0] * (10-view);
+ out[1] = out_dir[1] * view + out[1] * (10-view);
+ out[2] = out_dir[2] * view + out[2] * (10-view);
Normalize(out);
+ VecCopyf(area_normal, out);
}
-static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_verts)
+static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- float area_normal[3];
- ActiveData *node= active_verts->first;
- float* buffer;
-
- calc_area_normal(sd, ss, area_normal, active_verts);
-
- buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-
- while(node){
- float *co= ss->mvert[node->Index].co;
+ Brush *brush = paint_brush(&sd->paint);
+ float offset[3], area_normal[3];
+ float bstrength= ss->cache->bstrength;
+ int n;
+
+ /* area normal */
+ calc_area_normal(sd, ss, area_normal, nodes, totnode);
+
+ /* offset with as much as possible factored in already */
+ offset[0]= area_normal[0]*ss->cache->radius*ss->cache->scale[0]*bstrength;
+ offset[1]= area_normal[1]*ss->cache->radius*ss->cache->scale[1]*bstrength;
+ offset[2]= area_normal[2]*ss->cache->radius*ss->cache->scale[2]*bstrength;
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
+
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
- const float val[3]= {co[0]+area_normal[0]*ss->cache->radius*node->Fade*ss->cache->scale[0],
- co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1],
- co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]};
+ while(sculpt_node_verts_next(&vd)) {
+ /* offset vertex */
+ const float fade = tex_strength(ss, brush, vd.co, vd.dist);
+ const float val[3]= {vd.co[0] + offset[0]*fade,
+ vd.co[1] + offset[1]*fade,
+ vd.co[2] + offset[2]*fade};
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
+ sculpt_clip(sd, ss, vd.co, val);
}
- sculpt_clip(sd, ss, co, val);
-
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
/* For the smooth brush, uses the neighboring vertices around vert to calculate
@@ -379,69 +674,67 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
VecCopyf(avg, ss->mvert[vert].co);
}
-static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
+static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- ActiveData *node= active_verts->first;
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
- int i;
-
- for(i = 0; i < 2; ++i) {
- while(node){
- float *co= ss->mvert[node->Index].co;
- float avg[3], val[3];
-
- neighbor_average(ss, avg, node->Index);
- val[0] = co[0]+(avg[0]-co[0])*node->Fade;
- val[1] = co[1]+(avg[1]-co[1])*node->Fade;
- val[2] = co[2]+(avg[2]-co[2])*node->Fade;
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ int iteration, n;
+
+ for(iteration = 0; iteration < 2; ++iteration) {
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
- sculpt_clip(s, ss, co, val);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(s, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+
+ while(sculpt_node_verts_next(&vd)) {
+ const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+ float avg[3], val[3];
+
+ neighbor_average(ss, avg, vd.index);
+ val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade;
+ val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade;
+ val[2] = vd.co[2]+(avg[2]-vd.co[2])*fade;
+
+ sculpt_clip(sd, ss, vd.co, val);
}
- node= node->next;
+
+ BLI_pbvh_node_mark_update(nodes[n]);
}
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
+static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- ActiveData *node= active_verts->first;
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ int n;
- while(node) {
- float *co= ss->mvert[node->Index].co;
- const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade,
- co[1]+(ss->cache->location[1]-co[1])*node->Fade,
- co[2]+(ss->cache->location[2]-co[2])*node->Fade};
-
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(s, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
+
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+
+ while(sculpt_node_verts_next(&vd)) {
+ const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+ const float val[3]= {vd.co[0]+(vd.location[0]-vd.co[0])*fade,
+ vd.co[1]+(vd.location[1]-vd.co[1])*fade,
+ vd.co[2]+(vd.location[2]-vd.co[2])*fade};
+
+ sculpt_clip(sd, ss, vd.co, val);
}
- sculpt_clip(s, ss, co, val);
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void do_grab_brush(Sculpt *sd, SculptSession *ss)
+static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
ActiveData *node= ss->cache->grab_active_verts[ss->cache->symmetry].first;
float add[3];
float grab_delta[3];
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
+ int n;
VecCopyf(grab_delta, ss->cache->grab_delta_symmetry);
@@ -452,122 +745,120 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss)
VecMulf(add, node->Fade);
VecAddf(add, add, co);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], add);
- cur = cur->next;
- }
- }
-
sculpt_clip(sd, ss, co, add);
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
-
+
+ for(n=0; n<totnode; n++)
+ BLI_pbvh_node_mark_update(nodes[n]);
}
-static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts)
+static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
float area_normal[3];
- ActiveData *node= active_verts->first;
- float *buffer;
float lim= ss->cache->radius / 4;
+ int n;
if(ss->cache->flip)
lim = -lim;
- calc_area_normal(sd, ss, area_normal, active_verts);
+ calc_area_normal(sd, ss, area_normal, nodes, totnode);
- buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
- while(node){
- float *disp= &ss->layer_disps[node->Index];
- float *co= ss->mvert[node->Index].co;
- float val[3];
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
- *disp+= node->Fade;
-
- /* Don't let the displacement go past the limit */
- if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
- *disp = lim;
-
- val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0];
- val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1];
- val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2];
-
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
- }
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
- sculpt_clip(sd, ss, co, val);
+ while(sculpt_node_verts_next(&vd)) {
+ const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+ float *disp= &ss->layer_disps[vd.index];
+ float val[3];
+
+ *disp+= fade;
+
+ /* Don't let the displacement go past the limit */
+ if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
+ *disp = lim;
+
+ val[0] = ss->mesh_co_orig[vd.index][0]+area_normal[0] * *disp*ss->cache->scale[0];
+ val[1] = ss->mesh_co_orig[vd.index][1]+area_normal[1] * *disp*ss->cache->scale[1];
+ val[2] = ss->mesh_co_orig[vd.index][2]+area_normal[2] * *disp*ss->cache->scale[2];
- node= node->next;
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts)
+static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- ActiveData *node= active_verts->first;
- float add[3];
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ int n;
- while(node) {
- float *co= ss->mvert[node->Index].co;
- short *no= ss->mvert[node->Index].no;
-
- add[0]= no[0]/ 32767.0f;
- add[1]= no[1]/ 32767.0f;
- add[2]= no[2]/ 32767.0f;
- VecMulf(add, node->Fade * ss->cache->radius);
- add[0]*= ss->cache->scale[0];
- add[1]*= ss->cache->scale[1];
- add[2]*= ss->cache->scale[2];
- VecAddf(add, add, co);
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(s, ss, &buffer[cur->element*3], add);
- cur = cur->next;
- }
- }
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
- sculpt_clip(s, ss, co, add);
+ while(sculpt_node_verts_next(&vd)) {
+ const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+ float add[3];
+
+ add[0]= vd.no[0]/32767.0f;
+ add[1]= vd.no[1]/32767.0f;
+ add[2]= vd.no[2]/32767.0f;
+ VecMulf(add, fade * ss->cache->radius);
+ add[0]*= ss->cache->scale[0];
+ add[1]*= ss->cache->scale[1];
+ add[2]*= ss->cache->scale[2];
+ VecAddf(add, add, vd.co);
+
+ sculpt_clip(sd, ss, vd.co, add);
+ }
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3])
+static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float co[3])
{
- ActiveData *outer[FLATTEN_SAMPLE_SIZE];
- int i;
+ float outer_dist[FLATTEN_SAMPLE_SIZE];
+ int outer_index[FLATTEN_SAMPLE_SIZE];
+ int i, n;
- for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
- outer[i] = node;
+ for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
+ outer_index[i] = 0;
+ outer_dist[i]= -1.0f;
+ }
- for(; node; node = node->next) {
- for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
- if(node->dist > outer[i]->dist) {
- outer[i] = node;
- break;
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
+
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
+
+ while(sculpt_node_verts_next(&vd)) {
+ for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
+ if(vd.dist > outer_dist[i]) {
+ outer_index[i] = vd.index;
+ break;
+ }
}
}
+
+ BLI_pbvh_node_mark_update(nodes[n]);
}
co[0] = co[1] = co[2] = 0.0f;
for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
- VecAddf(co, co, ss->mvert[outer[i]->Index].co);
+ VecAddf(co, co, ss->mvert[outer_index[i]].co);
VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE);
}
@@ -599,16 +890,17 @@ static int plane_point_side(float co[3], float plane_normal[3], float plane_cent
return d <= 0.0f;
}
-static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts, int clay)
+static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, int clay)
{
- ActiveData *node= active_verts->first;
/* area_normal and cntr define the plane towards which vertices are squashed */
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
float area_normal[3];
float cntr[3], cntr2[3], bstr = 0;
- int flip = 0;
- float *buffer;
- calc_area_normal(sd, ss, area_normal, active_verts);
- calc_flatten_center(ss, node, cntr);
+ int n, flip = 0;
+
+ calc_area_normal(sd, ss, area_normal, nodes, totnode);
+ calc_flatten_center(sd, ss, nodes, totnode, cntr);
if(clay) {
bstr= brush_strength(sd, ss->cache);
@@ -619,287 +911,152 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
flip = bstr < 0;
}
- buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-
- while(node){
- float *co= ss->mvert[node->Index].co;
- float intr[3], val[3];
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptVertexData vd;
- if(!clay || plane_point_side(co, area_normal, cntr2, flip)) {
- /* Find the intersection between squash-plane and vertex (along the area normal) */
- point_plane_project(intr, co, area_normal, cntr);
+ sculpt_node_verts_init(sd, ss, nodes[n], &vd);
- VecSubf(val, intr, co);
+ while(sculpt_node_verts_next(&vd)) {
+ float intr[3], val[3];
+
+ if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) {
+ const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
- if(clay) {
- if(bstr > FLT_EPSILON)
- VecMulf(val, node->Fade / bstr);
- else
- VecMulf(val, node->Fade);
- /* Clay displacement */
- val[0]+=area_normal[0] * ss->cache->scale[0]*node->Fade;
- val[1]+=area_normal[1] * ss->cache->scale[1]*node->Fade;
- val[2]+=area_normal[2] * ss->cache->scale[2]*node->Fade;
- }
- else
- VecMulf(val, fabs(node->Fade));
+ /* Find the intersection between squash-plane and vertex (along the area normal) */
+ point_plane_project(intr, vd.co, area_normal, cntr);
- VecAddf(val, val, co);
+ VecSubf(val, intr, vd.co);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], val);
- cur = cur->next;
+ if(clay) {
+ if(bstr > FLT_EPSILON)
+ VecMulf(val, fade / bstr);
+ else
+ VecMulf(val, fade);
+ /* Clay displacement */
+ val[0]+=area_normal[0] * ss->cache->scale[0]*fade;
+ val[1]+=area_normal[1] * ss->cache->scale[1]*fade;
+ val[2]+=area_normal[2] * ss->cache->scale[2]*fade;
}
- }
- sculpt_clip(sd, ss, co, val);
-
- }
-
- node= node->next;
- }
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
-}
-
-/* Uses symm to selectively flip any axis of a coordinate. */
-static void flip_coord(float out[3], float in[3], const char symm)
-{
- if(symm & SCULPT_SYMM_X)
- out[0]= -in[0];
- else
- out[0]= in[0];
- if(symm & SCULPT_SYMM_Y)
- out[1]= -in[1];
- else
- out[1]= in[1];
- if(symm & SCULPT_SYMM_Z)
- out[2]= -in[2];
- else
- out[2]= in[2];
-}
-
-/* Get a pixel from the texcache at (px, py) */
-static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
-{
- unsigned *p;
- p = ss->texcache + py * ss->texcache_side + px;
- return ((unsigned char*)(p))[0];
-}
-
-static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
-{
- int x, y, x2, y2;
- const int tc_max = ss->texcache_side - 1;
- float urat, vrat, uopp;
-
- if(u < 0) u = 0;
- else if(u >= ss->texcache_side) u = tc_max;
- if(v < 0) v = 0;
- else if(v >= ss->texcache_side) v = tc_max;
-
- x = floor(u);
- y = floor(v);
- x2 = x + 1;
- y2 = y + 1;
-
- if(x2 > ss->texcache_side) x2 = tc_max;
- if(y2 > ss->texcache_side) y2 = tc_max;
-
- urat = u - x;
- vrat = v - y;
- uopp = 1 - urat;
-
- return ((get_texcache_pixel(ss, x, y) * uopp +
- get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) +
- (get_texcache_pixel(ss, x, y2) * uopp +
- get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
-}
-
-/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len)
-{
- Brush *br = paint_brush(&sd->paint);
- MTex *tex = NULL;
- float avg= 1;
-
- if(br->texact >= 0)
- tex = br->mtex[br->texact];
-
- if(!tex) {
- avg= 1;
- }
- else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
- float jnk;
-
- /* Get strength by feeding the vertex
- location directly into a texture */
- externtex(tex, point, &avg,
- &jnk, &jnk, &jnk, &jnk);
- }
- else if(ss->texcache) {
- const float bsize= ss->cache->pixel_radius * 2;
- const float rot= tex->rot + ss->cache->rotation;
- int px, py;
- float flip[3], point_2d[2];
+ else
+ VecMulf(val, fabs(fade));
- /* If the active area is being applied for symmetry, flip it
- across the symmetry axis in order to project it. This insures
- that the brush texture will be oriented correctly. */
- VecCopyf(flip, point);
- flip_coord(flip, flip, ss->cache->symmetry);
- projectf(ss->cache->mats, flip, point_2d);
+ VecAddf(val, val, vd.co);
- /* For Tile and Drag modes, get the 2D screen coordinates of the
- and scale them up or down to the texture size. */
- if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- const int sx= (const int)tex->size[0];
- const int sy= (const int)tex->size[1];
-
- float fx= point_2d[0];
- float fy= point_2d[1];
-
- float angle= atan2(fy, fx) - rot;
- float flen= sqrtf(fx*fx + fy*fy);
-
- if(rot<0.001 && rot>-0.001) {
- px= point_2d[0];
- py= point_2d[1];
- } else {
- px= flen * cos(angle) + 2000;
- py= flen * sin(angle) + 2000;
+ sculpt_clip(sd, ss, vd.co, val);
}
- if(sx != 1)
- px %= sx-1;
- if(sy != 1)
- py %= sy-1;
- avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
}
- else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
- float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize;
- float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize;
- float angle= atan2(fy, fx) - rot;
- float flen= sqrtf(fx*fx + fy*fy);
-
- fx = flen * cos(angle) + 0.5;
- fy = flen * sin(angle) + 0.5;
-
- avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
- }
+ BLI_pbvh_node_mark_update(nodes[n]);
}
-
- avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
-
- return avg;
}
-/* Mark area around the brush as damaged. projverts are marked if they are
- inside the area and the damaged rectangle in 2D screen coordinates is
- added to damaged_rects. */
-static void sculpt_add_damaged_rect(SculptSession *ss)
+static void sculpt_brush_hit_cb(PBVHNode *node, void *data_v)
{
- short p[2];
- RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode");
- const float radius = MAX2(ss->cache->pixel_radius, ss->cache->previous_pixel_radius);
- unsigned i;
+ SculptSearchSphereData *data = data_v;
+ int i, totvert, *verts;
- /* Find center */
- project(ss->cache->mats, ss->cache->location, p);
- rn->r.xmin= p[0] - radius;
- rn->r.ymin= p[1] - radius;
- rn->r.xmax= p[0] + radius;
- rn->r.ymax= p[1] + radius;
+ BLI_pbvh_node_get_verts(node, &verts, &totvert);
- BLI_addtail(&ss->damaged_rects, rn);
+ /* XXX: for now grab brush still uses an active vert list,
+ will be fixed later */
- /* Update insides */
- for(i=0; i<ss->totvert; ++i) {
- if(!ss->projverts[i].inside) {
- if(ss->projverts[i].co[0] > rn->r.xmin && ss->projverts[i].co[1] > rn->r.ymin &&
- ss->projverts[i].co[0] < rn->r.xmax && ss->projverts[i].co[1] < rn->r.ymax) {
- ss->projverts[i].inside= 1;
- }
+ for(i = 0; i < totvert; ++i) {
+ int v = verts[i];
+ float delta[3], dsq;
+
+ VecSubf(delta, data->ss->mvert[v].co,
+ data->ss->cache->location);
+ dsq = Inpf(delta, delta);
+
+ if(dsq < data->radius_squared) {
+ ActiveData *adata =
+ (ActiveData*)MEM_mallocN(sizeof(ActiveData),
+ "ActiveData");
+ adata->Index = v;
+ adata->dist = sqrt(dsq);
+ BLI_addtail(data->active_verts, adata);
}
- // XXX: remember to fix this!
- // temporary pass
- ss->projverts[i].inside = 1;
}
+
+ BLI_pbvh_node_mark_update(node);
}
static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
{
Brush *brush = paint_brush(&sd->paint);
- float av_dist;
- ListBase active_verts={0,0};
- ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry];
- ActiveData *adata= 0;
- float *vert;
- Mesh *me= NULL; /*XXX: get_mesh(OBACT); */
- const float bstrength= brush_strength(sd, cache);
- KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
- Brush *b = brush;
- int i;
+ //KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
+ PBVHNode **nodes= NULL;
+ int totnode;
+ SculptSearchSphereData data;
- sculpt_add_damaged_rect(ss);
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = ss->cache->radius * ss->cache->radius;
/* Build a list of all vertices that are potentially within the brush's
- area of influence. Only do this once for the grab brush. */
- if((b->sculpt_tool != SCULPT_TOOL_GRAB) || cache->first_time) {
- for(i=0; i<ss->totvert; ++i) {
- /* Projverts.inside provides a rough bounding box */
- if(ss->multires || ss->projverts[i].inside) {
- //vert= ss->vertexcosnos ? &ss->vertexcosnos[i*6] : a->verts[i].co;
- vert= ss->mvert[i].co;
- av_dist= VecLenf(ss->cache->location, vert);
- if(av_dist < cache->radius) {
- adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData");
-
- adata->Index = i;
- /* Fade is used to store the final strength at which the brush
- should modify a particular vertex. */
- adata->Fade= tex_strength(sd, ss, vert, av_dist) * bstrength;
- adata->dist = av_dist;
-
- if(b->sculpt_tool == SCULPT_TOOL_GRAB && cache->first_time)
- BLI_addtail(grab_active_verts, adata);
- else
- BLI_addtail(&active_verts, adata);
- }
- }
+ area of influence */
+ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ if(cache->first_time) {
+ const float bstrength= brush_strength(sd, cache);
+ ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry];
+ ActiveData *adata;
+
+ data.active_verts = grab_active_verts;
+ BLI_pbvh_search_callback(ss->tree, sculpt_search_sphere_cb, &data,
+ sculpt_brush_hit_cb, &data);
+
+ BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data,
+ &nodes, &totnode);
+
+ ss->cache->grab_active_nodes[ss->cache->symmetry]= nodes;
+ ss->cache->grab_active_totnode[ss->cache->symmetry]= totnode;
+
+ /* Update brush strength for each vertex */
+ for(adata = data.active_verts->first; adata; adata = adata->next)
+ adata->Fade = tex_strength(ss, brush, ss->mvert[adata->Index].co, adata->dist) * bstrength;
+ }
+ else {
+ nodes= ss->cache->grab_active_nodes[ss->cache->symmetry];
+ totnode= ss->cache->grab_active_totnode[ss->cache->symmetry];
}
}
+ else {
+ BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data,
+ &nodes, &totnode);
+ }
/* Only act if some verts are inside the brush area */
- if(active_verts.first || (b->sculpt_tool == SCULPT_TOOL_GRAB && grab_active_verts->first)) {
+ if(totnode) {
/* Apply one type of brush action */
- switch(b->sculpt_tool){
+ switch(brush->sculpt_tool){
case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ss, &active_verts);
+ do_draw_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
- do_smooth_brush(sd, ss, &active_verts);
+ do_smooth_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ss, &active_verts);
+ do_pinch_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ss, &active_verts);
+ do_inflate_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ss);
+ do_grab_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ss, &active_verts);
+ do_layer_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_clay_brush(sd, ss, &active_verts, 0);
+ do_flatten_clay_brush(sd, ss, nodes, totnode, 0);
break;
case SCULPT_TOOL_CLAY:
- do_flatten_clay_brush(sd, ss, &active_verts, 1);
+ do_flatten_clay_brush(sd, ss, nodes, totnode, 1);
+ break;
}
+#if 0
/* Copy the modified vertices from mesh to the active key */
if(keyblock && !ss->multires) {
float *co= keyblock->data;
@@ -919,9 +1076,14 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
BLI_freelistN(&active_verts);
else {
if(b->sculpt_tool != SCULPT_TOOL_GRAB)
- addlisttolist(&ss->damaged_verts, &active_verts);
+ addlisttolist(&ss->modified_verts, &active_verts);
}
- }
+#endif
+
+ if(brush->sculpt_tool != SCULPT_TOOL_GRAB)
+ if(nodes)
+ MEM_freeN(nodes);
+ }
}
/* Flip all the editdata across the axis/axes specified by symm. Used to
@@ -943,6 +1105,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
VecCopyf(cache->location, cache->true_location);
VecCopyf(cache->grab_delta_symmetry, cache->grab_delta);
cache->symmetry = 0;
+ cache->bstrength = brush_strength(sd, cache);
do_brush_action(sd, ss, cache);
for(i = 1; i <= symm; ++i) {
@@ -955,110 +1118,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
cache->first_time = 0;
}
-static void add_face_normal(vec3f *norm, MVert *mvert, const MFace* face, float *fn)
-{
- vec3f c= {mvert[face->v1].co[0],mvert[face->v1].co[1],mvert[face->v1].co[2]};
- vec3f b= {mvert[face->v2].co[0],mvert[face->v2].co[1],mvert[face->v2].co[2]};
- vec3f a= {mvert[face->v3].co[0],mvert[face->v3].co[1],mvert[face->v3].co[2]};
- vec3f s1, s2;
- float final[3];
-
- VecSubf(&s1.x,&a.x,&b.x);
- VecSubf(&s2.x,&c.x,&b.x);
-
- final[0] = s1.y * s2.z - s1.z * s2.y;
- final[1] = s1.z * s2.x - s1.x * s2.z;
- final[2] = s1.x * s2.y - s1.y * s2.x;
-
- if(fn)
- VecCopyf(fn, final);
-
- norm->x+= final[0];
- norm->y+= final[1];
- norm->z+= final[2];
-}
-
-static void update_damaged_vert(SculptSession *ss, ListBase *lb)
-{
- ActiveData *vert;
-
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->normals ):0;
- for(vert= lb->first; vert; vert= vert->next) {
- vec3f norm= {0,0,0};
- IndexNode *face= ss->fmap[vert->Index].first;
-
- while(face){
- float *fn = NULL;
- if(ss->face_normals)
- fn = &ss->face_normals[face->index*3];
- add_face_normal(&norm, ss->mvert, &ss->mface[face->index], fn);
- face= face->next;
- }
- Normalize(&norm.x);
-
- ss->mvert[vert->Index].no[0]=norm.x*32767;
- ss->mvert[vert->Index].no[1]=norm.y*32767;
- ss->mvert[vert->Index].no[2]=norm.z*32767;
-
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[vert->Index];
- while( cur != 0 && cur->element != -1 ) {
- int i = ss->drawobject->faceRemap[cur->element/3];
- if( ss->mface[i].flag & ME_SMOOTH ) {
- VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
- }
- else {
- float norm[3];
- if( ss->mface[i].v4 )
- CalcNormFloat4(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, ss->mvert[ss->mface[i].v4].co, norm);
- else
- CalcNormFloat(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, norm);
- VECCOPY(&buffer[(cur->element-cur->element%3)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+1)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+2)*3],norm);
-
- /* maybe this was a quad - need to update the other triangle of the quad */
- if( ss->drawobject->faceRemap[cur->element/3-1] == i ) {
- VECCOPY(&buffer[(cur->element-cur->element%3-3)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3-2)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3-1)*3],norm);
- }
- if( ss->drawobject->faceRemap[cur->element/3+1] == i ) {
- VECCOPY(&buffer[(cur->element-cur->element%3+3)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+4)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+5)*3],norm);
- }
- }
-
- //VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
- cur = cur->next;
- }
- }
- }
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->normals );
-}
-
-static void calc_damaged_verts(SculptSession *ss)
-{
- int i;
-
- for(i=0; i<8; ++i)
- update_damaged_vert(ss, &ss->cache->grab_active_verts[i]);
- update_damaged_vert(ss, &ss->damaged_verts);
- BLI_freelistN(&ss->damaged_verts);
- ss->damaged_verts.first = ss->damaged_verts.last = NULL;
-}
-
-#if 0
-static void projverts_clear_inside(SculptSession *ss)
-{
- int i;
- for(i = 0; i < ss->totvert; ++i)
- ss->projverts[i].inside = 0;
-}
-#endif
-
static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
{
Brush *brush = paint_brush(&sd->paint);
@@ -1076,20 +1135,6 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
}
}
-static void sculptmode_update_all_projverts(SculptSession *ss)
-{
- unsigned i;
-
- if(!ss->projverts)
- ss->projverts = MEM_mallocN(sizeof(ProjVert)*ss->totvert,"ProjVerts");
-
- for(i=0; i<ss->totvert; ++i) {
- project(ss->cache->mats, ss->vertexcosnos ? &ss->vertexcosnos[i * 6] : ss->mvert[i].co,
- ss->projverts[i].co);
- ss->projverts[i].inside= 0;
- }
-}
-
/* Checks whether full update mode (slower) needs to be used to work with modifiers */
char sculpt_modifiers_active(Object *ob)
{
@@ -1130,12 +1175,12 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
static void sculpt_update_mesh_elements(bContext *C)
{
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;
- int oldtotvert = ss->totvert;
- DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
if((ss->multires = sculpt_multires_active(ob))) {
- //DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
ss->totvert = dm->getNumVerts(dm);
ss->totface = dm->getNumFaces(dm);
ss->mvert = dm->getVertDataArray(dm, CD_MVERT);
@@ -1148,24 +1193,12 @@ static void sculpt_update_mesh_elements(bContext *C)
ss->totface = me->totface;
ss->mvert = me->mvert;
ss->mface = me->mface;
- ss->face_normals = NULL;
- }
- if( GPU_buffer_legacy( dm ) ) {
- ss->drawobject = 0;
- }
- else {
- ss->drawobject = dm->drawObject;
+ if(!ss->face_normals)
+ ss->face_normals = MEM_callocN(sizeof(float) * 3 * me->totface, "sculpt face normals");
}
- if(ss->totvert != oldtotvert) {
- if(ss->projverts) MEM_freeN(ss->projverts);
- ss->projverts = NULL;
-
- if(ss->fmap) MEM_freeN(ss->fmap);
- if(ss->fmap_mem) MEM_freeN(ss->fmap_mem);
- create_vert_face_map(&ss->fmap, &ss->fmap_mem, ss->mface, ss->totvert, ss->totface);
- ss->fmap_size = ss->totvert;
- }
+ ss->tree = dm->getPBVH(dm);
+ ss->fmap = dm->getFaceMap(dm);
}
static int sculpt_mode_poll(bContext *C)
@@ -1251,15 +1284,13 @@ static void SCULPT_OT_radial_control(wmOperatorType *ot)
/**** Operator for applying a stroke (various attributes including mouse path)
using the current brush. ****/
-static float unproject_brush_radius(SculptSession *ss, float offset)
+static float unproject_brush_radius(ViewContext *vc, float center[3], float offset)
{
- float brush_edge[3];
-
- /* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */
- view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
- ss->cache->initial_mouse[1], ss->cache->depth);
+ float delta[3];
- return VecLenf(ss->cache->true_location, brush_edge);
+ initgrabz(vc->rv3d, center[0], center[1], center[2]);
+ window_to_3d_delta(vc->ar, delta, offset, 0);
+ return VecLength(delta);
}
static void sculpt_cache_free(StrokeCache *cache)
@@ -1271,8 +1302,11 @@ static void sculpt_cache_free(StrokeCache *cache)
MEM_freeN(cache->face_norms);
if(cache->mats)
MEM_freeN(cache->mats);
- for(i = 0; i < 8; ++i)
+ for(i = 0; i < 8; ++i) {
BLI_freelistN(&cache->grab_active_verts[i]);
+ if(cache->grab_active_nodes[i])
+ MEM_freeN(cache->grab_active_nodes[i]);
+ }
MEM_freeN(cache);
}
@@ -1290,15 +1324,17 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
cache->flag = RNA_int_get(op->ptr, "flag");
RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance);
RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse);
- cache->depth = RNA_float_get(op->ptr, "depth");
cache->mouse[0] = cache->initial_mouse[0];
cache->mouse[1] = cache->initial_mouse[1];
/* Truly temporary data that isn't stored in properties */
+ cache->vc = vc;
+ cache->brush = brush;
+
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
- view3d_get_transformation(vc, vc->obact, cache->mats);
+ view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
sculpt_update_mesh_elements(C);
@@ -1338,14 +1374,14 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
}
}
- view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
- cache->initial_radius = unproject_brush_radius(ss, brush->size);
+ //view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
+ cache->initial_radius = unproject_brush_radius(vc, cache->true_location, brush->size);
cache->rotation = 0;
cache->first_time = 1;
}
/* Initialize the stroke cache variants from operator properties */
-static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerRNA *ptr)
+static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
@@ -1375,7 +1411,8 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
cache->pixel_radius = sqrt(dx*dx + dy*dy);
- cache->radius = unproject_brush_radius(ss, cache->pixel_radius);
+ cache->radius = unproject_brush_radius(paint_stroke_view_context(stroke),
+ cache->true_location, cache->pixel_radius);
cache->rotation = atan2(dy, dx);
}
else if(brush->flag & BRUSH_RAKE) {
@@ -1398,13 +1435,103 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
/* Find the grab delta */
if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+ // XXX: view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+ initgrabz(cache->vc->rv3d, cache->true_location[0], cache->true_location[1], cache->true_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
if(!cache->first_time)
VecSubf(cache->grab_delta, grab_location, cache->old_grab_location);
VecCopyf(cache->old_grab_location, grab_location);
}
}
+/* XXX: Code largely copied from bvhutils.c, should be unified */
+/* Returns 1 if a better intersection has been found */
+static int ray_face_intersection(float ray_start[3], float ray_normal[3],
+ float *t0, float *t1, float *t2, float *t3,
+ float *fdist)
+{
+ int hit = 0;
+
+ do
+ {
+ float dist = FLT_MAX;
+
+ if(!RayIntersectsTriangle(ray_start, ray_normal, t0, t1, t2,
+ &dist, NULL))
+ dist = FLT_MAX;
+
+ if(dist >= 0 && dist < *fdist) {
+ hit = 1;
+ *fdist = dist;
+ }
+
+ t1 = t2;
+ t2 = t3;
+ t3 = NULL;
+
+ } while(t2);
+
+ return hit;
+}
+
+typedef struct {
+ SculptSession *ss;
+ float *ray_start, *ray_normal;
+ int hit;
+ float dist;
+} SculptRaycastData;
+
+void sculpt_raycast_cb(PBVHNode *node, void *data_v)
+{
+ SculptRaycastData *srd = data_v;
+ MVert *vert = srd->ss->mvert;
+ int i, totface, *faces;
+
+ BLI_pbvh_node_get_faces(node, &faces, &totface);
+
+ for(i = 0; i < totface; ++i) {
+ MFace *f = srd->ss->mface + faces[i];
+ if(ray_face_intersection(srd->ray_start, srd->ray_normal,
+ vert[f->v1].co,
+ vert[f->v2].co,
+ vert[f->v3].co,
+ f->v4 ? vert[f->v4].co : NULL,
+ &srd->dist)) {
+ srd->hit = faces[i];
+ }
+ }
+}
+
+/* Do a raycast in the tree to find the 3d brush location
+ (This allows us to ignore the GL depth buffer)
+ Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
+ */
+int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2])
+{
+ ViewContext *vc = paint_stroke_view_context(stroke);
+ float ray_start[3], ray_normal[3];
+ float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
+ mouse[1] - vc->ar->winrct.ymin};
+ SculptRaycastData srd;
+
+ viewray(vc->ar, vc->v3d, mval, ray_start, ray_normal);
+
+ srd.ss = vc->obact->sculpt;
+ srd.ray_start = ray_start;
+ 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);
+
+ VecCopyf(out, ray_normal);
+ VecMulf(out, srd.dist);
+ VecAddf(out, out, ray_start);
+
+ return srd.hit != -1;
+}
+
/* Initialize stroke operator properties */
static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss)
{
@@ -1442,9 +1569,6 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
mouse[1] = event->y;
RNA_float_set_array(op->ptr, "initial_mouse", mouse);
- /* Initial screen depth under the mouse */
- RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y));
-
sculpt_update_cache_invariants(sd, ss, C, op);
}
@@ -1467,30 +1591,16 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
- float *buffer= NULL;
int i;
/* Restore the mesh before continuing with anchored stroke */
if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) {
-
- if(ss->drawobject)
- buffer= (float *)GPU_buffer_lock(ss->drawobject->normals);
-
for(i = 0; i < ss->totvert; ++i) {
VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]);
ss->mvert[i].no[0] = cache->orig_norms[i][0];
ss->mvert[i].no[1] = cache->orig_norms[i][1];
ss->mvert[i].no[2] = cache->orig_norms[i][2];
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[i];
- while( cur != 0 && cur->element != -1 ) {
- VECCOPY(&buffer[cur->element*3],cache->orig_norms[i]);
- cur = cur->next;
- }
- }
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->normals );
if(ss->face_normals) {
float *fn = ss->face_normals;
@@ -1503,20 +1613,14 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
}
}
-static void sculpt_post_stroke_free(SculptSession *ss)
-{
- BLI_freelistN(&ss->damaged_rects);
- BLI_freelistN(&ss->damaged_verts);
-}
-
static void sculpt_flush_update(bContext *C)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
-
- calc_damaged_verts(ss);
+ rcti r;
+ int redraw = 0;
if(mmd) {
if(mmd->undo_verts && mmd->undo_verts != ss->mvert)
@@ -1527,23 +1631,35 @@ static void sculpt_flush_update(bContext *C)
multires_mark_as_modified(ob);
}
- ED_region_tag_redraw(ar);
+ BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL, NULL);
+ redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r);
+
+ if(redraw) {
+ r.xmin += ar->winrct.xmin + 1;
+ r.xmax += ar->winrct.xmin - 1;
+ r.ymin += ar->winrct.ymin + 1;
+ r.ymax += ar->winrct.ymin - 1;
+
+ ss->partial_redraw = 1;
+ ED_region_tag_redraw_partial(ar, &r);
+ }
}
static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
{
- ViewContext vc;
- float cur_depth;
-
- view3d_set_viewcontext(C, &vc);
- cur_depth = read_cached_depth(&vc, event->x, event->y);
+ float mouse[2] = {event->x, event->y}, location[3];
+ int over_mesh;
- /* Don't start the stroke until a valid depth is found */
- if(cur_depth < 1.0 - FLT_EPSILON) {
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ over_mesh = sculpt_stroke_get_location(C, op->customdata, location, mouse);
+
+ /* Don't start the stroke until mouse goes over the mesh */
+ if(over_mesh) {
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
sculpt_brush_stroke_init_properties(C, op, event, ss);
- sculptmode_update_all_projverts(ss);
return 1;
}
@@ -1556,13 +1672,12 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
- sculpt_update_cache_variants(sd, ss, itemptr);
+ sculpt_update_cache_variants(sd, ss, stroke, itemptr);
sculpt_restore_mesh(sd, ss);
do_symmetrical_brush_actions(sd, ss);
/* Cleanup */
sculpt_flush_update(C);
- sculpt_post_stroke_free(ss);
}
static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
@@ -1571,9 +1686,8 @@ 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;
- request_depth_update(paint_stroke_view_context(stroke)->rv3d);
sculpt_cache_free(ss->cache);
ss->cache = NULL;
sculpt_undo_push(C, sd);
@@ -1584,7 +1698,8 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
{
sculpt_brush_stroke_init(C);
- op->customdata = paint_stroke_new(C, sculpt_stroke_test_start,
+ op->customdata = paint_stroke_new(C, sculpt_stroke_get_location,
+ sculpt_stroke_test_start,
sculpt_stroke_update_step,
sculpt_stroke_done);
@@ -1601,12 +1716,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
- op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done);
+ op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
+ sculpt_stroke_update_step, sculpt_stroke_done);
sculpt_brush_stroke_init(C);
sculpt_update_cache_invariants(sd, ss, C, op);
- sculptmode_update_all_projverts(ss);
paint_stroke_exec(C, op);
@@ -1649,9 +1764,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* The initial 2D location of the mouse */
RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
-
- /* The initial screen depth of the mouse */
- RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX);
}
/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
@@ -1688,6 +1800,13 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
/**** Toggle operator for turning sculpt mode on or off ****/
+static void sculpt_init_session(bContext *C, Object *ob)
+{
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+
+ sculpt_update_mesh_elements(C);
+}
+
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1713,7 +1832,8 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
/* Create sculpt mode session data */
if(ob->sculpt)
free_sculptsession(&ob->sculpt);
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+
+ sculpt_init_session(C, ob);
paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
@@ -1745,3 +1865,4 @@ void ED_operatortypes_sculpt()
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
}
+