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/sculpt.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1332
1 files changed, 964 insertions, 368 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index e2ed7776b7e..51500ab8e1c 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -40,10 +40,11 @@
#include "BLI_utildefines.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
-#include "BLI_pbvh.h"
#include "BLI_threads.h"
#include "BLI_rand.h"
+#include "BLF_translation.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
@@ -51,11 +52,13 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "BKE_pbvh.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
@@ -65,6 +68,7 @@
#include "BKE_report.h"
#include "BKE_lattice.h" /* for armature_deform_verts */
#include "BKE_node.h"
+#include "BKE_object.h"
#include "BKE_subsurf.h"
#include "BIF_glutil.h"
@@ -86,6 +90,8 @@
#include "GPU_buffers.h"
+#include "bmesh.h"
+
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -98,8 +104,13 @@ void ED_sculpt_force_update(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (ob && (ob->mode & OB_MODE_SCULPT))
+ if (ob && (ob->mode & OB_MODE_SCULPT)) {
multires_force_update(ob);
+
+ /* Set reorder=false so that saving the file doesn't reorder
+ * the BMesh's elements */
+ sculptsession_bm_to_me(ob, FALSE);
+ }
}
float *ED_sculpt_get_last_stroke(struct Object *ob)
@@ -129,6 +140,11 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
Mesh *me = (Mesh *)ob->data;
ModifierData *md;
+ if (ob->sculpt && ob->sculpt->bm) {
+ /* can't combine multires and dynamic topology */
+ return NULL;
+ }
+
if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
/* multires can't work without displacement layer */
return NULL;
@@ -172,7 +188,8 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
Mesh *me = (Mesh *)ob->data;
MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
- if (mmd) return 0;
+ if (mmd || ob->sculpt->bm)
+ return 0;
/* non-locked shape keys could be handled in the same way as deformed mesh */
if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
@@ -228,7 +245,6 @@ typedef struct StrokeCache {
float pressure;
float mouse[2];
float bstrength;
- float tex_mouse[2];
/* The rest is temporary storage that isn't saved as a property */
@@ -242,8 +258,8 @@ typedef struct StrokeCache {
Brush *brush;
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
- float special_rotation; /* Texture rotation (radians) for anchored and rake modes */
- int pixel_radius, previous_pixel_radius;
+
+ float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
@@ -267,8 +283,8 @@ typedef struct StrokeCache {
int radial_symmetry_pass;
float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4];
- float last_rake[2]; /* Last location of updating rake rotation */
int original;
+ float anchored_location[3];
float vertex_rotation;
@@ -281,12 +297,129 @@ typedef struct StrokeCache {
rcti previous_r; /* previous redraw rectangle */
} StrokeCache;
+/************** Access to original unmodified vertex data *************/
+
+typedef struct {
+ BMLog *bm_log;
+
+ SculptUndoNode *unode;
+ float (*coords)[3];
+ short (*normals)[3];
+ float *vmasks;
+
+ /* Original coordinate, normal, and mask */
+ const float *co;
+ float mask;
+ short no[3];
+} SculptOrigVertData;
+
+
+/* Initialize a SculptOrigVertData for accessing original vertex data;
+ * handles BMesh, mesh, and multires */
+static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data,
+ Object *ob,
+ SculptUndoNode *unode)
+{
+ SculptSession *ss = ob->sculpt;
+ BMesh *bm = ss->bm;
+
+ memset(data, 0, sizeof(*data));
+ data->unode = unode;
+
+ if (bm) {
+ data->bm_log = ss->bm_log;
+ }
+ else {
+ data->coords = data->unode->co;
+ data->normals = data->unode->no;
+ data->vmasks = data->unode->mask;
+ }
+}
+
+/* Initialize a SculptOrigVertData for accessing original vertex data;
+ * handles BMesh, mesh, and multires */
+static void sculpt_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node)
+{
+ SculptUndoNode *unode;
+ unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+ sculpt_orig_vert_data_unode_init(data, ob, unode);
+}
+
+/* Update a SculptOrigVertData for a particular vertex from the PBVH
+ * iterator */
+static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
+ PBVHVertexIter *iter)
+{
+ if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
+ if (orig_data->coords) {
+ orig_data->co = orig_data->coords[iter->i];
+ }
+ else {
+ orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
+ }
+
+ if (orig_data->normals) {
+ copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]);
+ }
+ else {
+ /* TODO: log doesn't store normals yet */
+ normal_float_to_short_v3(orig_data->no, iter->bm_vert->no);
+ }
+ }
+ else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
+ if (orig_data->vmasks) {
+ orig_data->mask = orig_data->vmasks[iter->i];
+ }
+ else {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ }
+ }
+}
+
+/**********************************************************************/
+
+/* Returns true if the stroke will use dynamic topology, false
+ otherwise.
+
+ Factors: some brushes like grab cannot do dynamic topology.
+ Others, like smooth, are better without. Same goes for alt-
+ key smoothing. */
+static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
+ const Brush *brush)
+{
+ return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
+
+ (!ss->cache || (!ss->cache->alt_smooth)) &&
+
+ /* Requires mesh restore, which doesn't work with
+ * dynamic-topology */
+ !(brush->flag & BRUSH_ANCHORED) &&
+ !(brush->flag & BRUSH_RESTORE_MESH) &&
+
+ (!ELEM6(brush->sculpt_tool,
+ /* These brushes, as currently coded, cannot
+ * support dynamic topology */
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER,
+
+ /* These brushes could handle dynamic topology,
+ * but user feedback indicates it's better not
+ * to */
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_MASK)));
+}
/*** paint mesh ***/
-static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss)
+static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
+ const Brush *brush = paint_brush(&sd->paint);
int i;
PBVHNode **nodes;
@@ -296,31 +429,47 @@ static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss)
(void)sd; /* quied unused warning */
#endif
- BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
+ * entries might be inserted by sculpt_undo_push_node() into the
+ * GHash used internally by BM_log_original_vert_co() by a
+ * different thread. [#33787] */
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP && !ss->bm)
for (n = 0; n < totnode; n++) {
SculptUndoNode *unode;
-
- unode = sculpt_undo_get_node(nodes[n]);
+ SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
+ SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+
+ if (ss->bm) {
+ unode = sculpt_undo_push_node(ob, nodes[n], type);
+ }
+ else {
+ unode = sculpt_undo_get_node(nodes[n]);
+ }
if (unode) {
PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ sculpt_orig_vert_data_unode_init(&orig_data, ob, unode);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (unode->type == SCULPT_UNDO_COORDS) {
- copy_v3_v3(vd.co, unode->co[vd.i]);
- if (vd.no) copy_v3_v3_short(vd.no, unode->no[vd.i]);
- else normal_short_to_float_v3(vd.fno, unode->no[vd.i]);
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
+ copy_v3_v3(vd.co, orig_data.co);
+ if (vd.no) copy_v3_v3_short(vd.no, orig_data.no);
+ else normal_short_to_float_v3(vd.fno, orig_data.no);
}
- else if (unode->type == SCULPT_UNDO_MASK) {
- *vd.mask = unode->mask[vd.i];
+ else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
+ *vd.mask = orig_data.mask;
}
if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
- BLI_pbvh_node_mark_update(nodes[n]);
+ BKE_pbvh_node_mark_update(nodes[n]);
}
}
@@ -347,7 +496,7 @@ static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
if (!pbvh)
return 0;
- BLI_pbvh_redraw_BB(pbvh, bb_min, bb_max);
+ BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max);
/* convert 3D bounding box to screen space */
if (!paint_convert_bb_to_rect(rect,
@@ -387,7 +536,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
/* clear redraw flag from nodes */
if (pbvh)
- BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
+ BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
}
/************************ Brush Testing *******************/
@@ -396,20 +545,42 @@ typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
+
+ /* View3d clipping - only set rv3d for clipping */
+ RegionView3D *clip_rv3d;
} SculptBrushTest;
static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
+ RegionView3D *rv3d = ss->cache->vc->rv3d;
+
test->radius_squared = ss->cache->radius_squared;
copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
+
+
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ test->clip_rv3d = rv3d;
+ }
+ else {
+ test->clip_rv3d = NULL;
+ }
}
-static int sculpt_brush_test(SculptBrushTest *test, float co[3])
+BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3])
+{
+ RegionView3D *rv3d = test->clip_rv3d;
+ return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
+}
+
+static int sculpt_brush_test(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
test->dist = sqrt(distsq);
return 1;
}
@@ -418,11 +589,14 @@ static int sculpt_brush_test(SculptBrushTest *test, float co[3])
}
}
-static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
+static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
if (distsq <= test->radius_squared) {
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
test->dist = distsq;
return 1;
}
@@ -433,6 +607,9 @@ static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
{
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
@@ -441,6 +618,10 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca
float side = M_SQRT1_2;
float local_co[3];
+ if (sculpt_brush_test_clipping(test, co)) {
+ return 0;
+ }
+
mul_v3_m4v3(local_co, local, co);
local_co[0] = fabs(local_co[0]);
@@ -510,7 +691,6 @@ static int sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float locat
/* ===== Sculpting =====
*
*/
-
static float overlapped_curve(Brush *br, float x)
{
@@ -734,32 +914,30 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
}
/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(SculptSession *ss, Brush *br, float point[3],
+static float tex_strength(SculptSession *ss, Brush *br,
+ const float point[3],
const float len,
const float sculpt_normal[3],
const short vno[3],
const float fno[3],
const float mask)
{
+ const Scene *scene = ss->cache->vc->scene;
MTex *mtex = &br->mtex;
float avg = 1;
+ float rgba[4];
if (!mtex->tex) {
avg = 1;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- float jnk;
-
/* Get strength by feeding the vertex
* location directly into a texture */
- externtex(mtex, point, &avg,
- &jnk, &jnk, &jnk, &jnk, 0);
+ avg = BKE_brush_sample_tex_3D(scene, br, point, rgba, 0, ss->tex_pool);
}
else if (ss->texcache) {
- float rotation = -mtex->rot;
float symm_point[3], point_2d[2];
float x = 0.0f, y = 0.0f; /* Quite warnings */
- float radius = 1.0f; /* Quite warnings */
/* if the active area is being applied for symmetry, flip it
* across the symmetry axis and rotate it back to the original
@@ -773,77 +951,33 @@ static float tex_strength(SculptSession *ss, Brush *br, float point[3],
ED_view3d_project_float_v2_m4(ss->cache->vc->ar, symm_point, point_2d, ss->cache->projection_mat);
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- /* keep coordinates relative to mouse */
-
- rotation += ss->cache->special_rotation;
-
- point_2d[0] -= ss->cache->tex_mouse[0];
- point_2d[1] -= ss->cache->tex_mouse[1];
-
- /* use pressure adjusted size for fixed mode */
- radius = ss->cache->pixel_radius;
-
- x = point_2d[0] + ss->cache->vc->ar->winrct.xmin;
- y = point_2d[1] + ss->cache->vc->ar->winrct.ymin;
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- /* leave the coordinates relative to the screen */
-
- /* use unadjusted size for tiled mode */
- radius = BKE_brush_size_get(ss->cache->vc->scene, br);
-
- x = point_2d[0];
- y = point_2d[1];
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
+ /* still no symmetry supported for other paint modes.
+ * Sculpt does it DIY */
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
/* Similar to fixed mode, but projects from brush angle
* rather than view direction */
- /* Rotation is handled by the brush_local_mat */
- rotation = 0;
-
mul_m4_v3(ss->cache->brush_local_mat, symm_point);
x = symm_point[0];
y = symm_point[1];
- }
- if (mtex->brush_map_mode != MTEX_MAP_MODE_AREA) {
- x /= ss->cache->vc->ar->winx;
- y /= ss->cache->vc->ar->winy;
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
- if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- x -= 0.5f;
- y -= 0.5f;
- }
-
- x *= ss->cache->vc->ar->winx / radius;
- y *= ss->cache->vc->ar->winy / radius;
- }
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
- /* it is probably worth optimizing for those cases where
- * the texture is not rotated by skipping the calls to
- * atan2, sqrtf, sin, and cos. */
- if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
- const float flen = sqrtf(x * x + y * y);
+ avg = paint_get_tex_pixel(br, x, y, ss->tex_pool);
- x = flen * cosf(angle);
- y = flen * sinf(angle);
+ avg += br->texture_sample_bias;
+ }
+ else {
+ const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
+ avg = BKE_brush_sample_tex_3D(scene, br, point_3d, rgba, 0, ss->tex_pool);
}
-
- x *= br->mtex.size[0];
- y *= br->mtex.size[1];
-
- x += br->mtex.ofs[0];
- y += br->mtex.ofs[1];
-
- avg = paint_get_tex_pixel(br, x, y);
}
- avg += br->texture_sample_bias;
-
/* Falloff curve */
avg *= BKE_brush_curve_strength(br, len, ss->cache->radius);
@@ -871,9 +1005,9 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
int i;
if (data->original)
- BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
+ BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
else
- BLI_pbvh_node_get_BB(node, bb_min, bb_max);
+ BKE_pbvh_node_get_BB(node, bb_min, bb_max);
for (i = 0; i < 3; ++i) {
if (bb_min[i] > center[i])
@@ -926,6 +1060,11 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
original = (paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
TRUE : ss->cache->original);
+ /* In general the original coords are not available with dynamic
+ * topology */
+ if (ss->bm)
+ original = FALSE;
+
(void)sd; /* unused w/o openmp */
zero_v3(an);
@@ -942,7 +1081,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
sculpt_brush_test_init(ss, &test);
if (original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
float fno[3];
@@ -951,10 +1090,10 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, vd.co)) {
if (vd.no) {
@@ -968,7 +1107,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
#pragma omp critical
@@ -1049,11 +1188,12 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3])
{
Object *ob = vc->obact;
float loc[3], mval_f[2] = {0.0f, 1.0f};
+ float zfac;
mul_v3_m4v3(loc, ob->imat, center);
- initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
+ zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL);
- ED_view3d_win_to_delta(vc->ar, mval_f, y);
+ ED_view3d_win_to_delta(vc->ar, mval_f, y, zfac);
normalize_v3(y);
add_v3_v3(y, ob->loc);
@@ -1210,6 +1350,71 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
return vmask[vert];
}
+/* Same logic as neighbor_average(), but for bmesh rather than mesh */
+static void bmesh_neighbor_average(float avg[3], BMVert *v)
+{
+ const int vfcount = BM_vert_face_count(v);
+
+ zero_v3(avg);
+
+ /* Don't modify corner vertices */
+ if (vfcount > 1) {
+ BMIter liter;
+ BMLoop *l;
+ int i, total = 0;
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+
+ for (i = 0; i < 3; i++) {
+ if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) {
+ add_v3_v3(avg, adj_v[i]->co);
+ total++;
+ }
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
+
+ copy_v3_v3(avg, v->co);
+}
+
+/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
+static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+{
+ BMIter liter;
+ BMLoop *l;
+ float avg = 0;
+ int i, total = 0;
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+
+ for (i = 0; i < 3; i++) {
+ BMVert *v2 = adj_v[i];
+ float *vmask = CustomData_bmesh_get(&bm->vdata,
+ v2->head.data,
+ CD_PAINT_MASK);
+ avg += (*vmask);
+ total++;
+ }
+ }
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ float *vmask = CustomData_bmesh_get(&bm->vdata,
+ v->head.data,
+ CD_PAINT_MASK);
+ return (*vmask);
+ }
+}
+
static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
{
Brush *brush = paint_brush(&sd->paint);
@@ -1220,7 +1425,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1248,7 +1453,48 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
+ ss->cache->view_normal, vd.no, vd.fno,
+ smooth_mask ? 0 : *vd.mask);
+ if (smooth_mask) {
+ float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0, 1);
+ }
+ else {
+ float avg[3], val[3];
+
+ bmesh_neighbor_average(avg, vd.bm_vert);
+ sub_v3_v3v3(val, avg, vd.co);
+ mul_v3_fl(val, fade);
+
+ add_v3_v3(val, vd.co);
+
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
@@ -1269,9 +1515,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
CLAMP(bstrength, 0.0f, 1.0f);
- BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
+ BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
NULL, &gridsize, &griddata, &gridadj);
- BLI_pbvh_get_grid_key(ss->pbvh, &key);
+ BKE_pbvh_get_grid_key(ss->pbvh, &key);
thread_num = 0;
#ifdef _OPENMP
@@ -1405,7 +1651,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
SculptSession *ss = ob->sculpt;
const int max_iterations = 4;
const float fract = 1.0f / max_iterations;
- PBVHType type = BLI_pbvh_type(ss->pbvh);
+ PBVHType type = BKE_pbvh_type(ss->pbvh);
int iteration, n, count;
float last;
@@ -1433,6 +1679,9 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
do_mesh_smooth_brush(sd, ss, nodes[n], strength,
smooth_mask);
break;
+ case PBVH_BMESH:
+ do_bmesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask);
+ break;
}
}
@@ -1462,7 +1711,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist,
@@ -1474,7 +1723,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
if (vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
}
@@ -1514,11 +1763,11 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
@@ -1532,7 +1781,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1570,11 +1819,11 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
@@ -1597,7 +1846,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1614,11 +1863,11 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1633,7 +1882,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1659,25 +1908,26 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode *unode;
SculptBrushTest test;
- float (*origco)[3];
- short (*origno)[3];
+ SculptOrigVertData orig_data;
float (*proxy)[3];
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- origno = unode->no;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
- ss->cache->sculpt_normal_symm, origno[vd.i],
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(ss, brush,
+ orig_data.co,
+ test.dist,
+ ss->cache->sculpt_normal_symm,
+ orig_data.no,
NULL, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1686,7 +1936,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1710,11 +1960,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1727,7 +1977,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1759,11 +2009,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1776,7 +2026,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1797,26 +2047,27 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode *unode;
SculptBrushTest test;
- float (*origco)[3];
- short (*origno)[3];
+ SculptOrigVertData orig_data;
float (*proxy)[3];
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- origno = unode->no;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(ss, brush,
+ orig_data.co,
+ test.dist,
ss->cache->sculpt_normal_symm,
- origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f);
+ orig_data.no,
+ NULL, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1824,7 +2075,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1850,36 +2101,37 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode *unode;
SculptBrushTest test;
- float (*origco)[3];
- short (*origno)[3];
+ SculptOrigVertData orig_data;
float (*proxy)[3];
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- origno = unode->no;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(ss, brush,
+ orig_data.co,
+ test.dist,
ss->cache->sculpt_normal_symm,
- origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f);
+ orig_data.no,
+ NULL, vd.mask ? *vd.mask : 0.0f);
- mul_v3_m4v3(proxy[vd.i], m, origco[vd.i]);
- sub_v3_v3(proxy[vd.i], origco[vd.i]);
+ mul_v3_m4v3(proxy[vd.i], m, orig_data.co);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
mul_v3_fl(proxy[vd.i], fade);
if (vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1901,25 +2153,25 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
- SculptUndoNode *unode;
- float (*origco)[3], *layer_disp;
+ SculptOrigVertData orig_data;
+ float *layer_disp;
/* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
+ /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- if (!unode->layer_disp) {
- #pragma omp critical
- unode->layer_disp = MEM_callocN(sizeof(float) * unode->totvert, "layer disp");
- }
-
- layer_disp = unode->layer_disp;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ #pragma omp critical
+ {
+ layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]);
+ }
+
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
ss->cache->sculpt_normal_symm,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -1941,7 +2193,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
add_v3_v3(val, ss->layer_co[index]);
}
else {
- add_v3_v3(val, origco[vd.i]);
+ add_v3_v3(val, orig_data.co);
}
sculpt_clip(sd, ss, vd.co, val);
@@ -1950,7 +2202,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1967,11 +2219,11 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1989,7 +2241,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2015,25 +2267,25 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
sculpt_brush_test_init(ss, &test);
- if (ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ if (ss->cache->original && unode->co) {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
add_v3_v3(private_fc, unode->co[vd.i]);
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, vd.co)) {
add_v3_v3(private_fc, vd.co);
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
#pragma omp critical
@@ -2082,8 +2334,8 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
sculpt_brush_test_init(ss, &test);
- if (ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ if (ss->cache->original && unode->co) {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
/* for area normal */
@@ -2097,10 +2349,10 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, vd.co)) {
/* for area normal */
@@ -2119,7 +2371,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
#pragma omp critical
@@ -2301,11 +2553,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
float intr[3];
@@ -2326,7 +2578,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2373,11 +2625,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
if (plane_point_side_flip(vd.co, an, fc, flip)) {
@@ -2401,7 +2653,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2475,11 +2727,11 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_cube(&test, vd.co, mat)) {
if (plane_point_side_flip(vd.co, sn, fc, flip)) {
@@ -2503,7 +2755,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2539,11 +2791,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
if (plane_point_side(vd.co, an, fc)) {
@@ -2567,7 +2819,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2603,11 +2855,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
if (!plane_point_side(vd.co, an, fc)) {
@@ -2631,7 +2883,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2688,6 +2940,65 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
BKE_key_convert_from_vertcos(ob, kb, vertCos);
}
+/* Note: we do the topology update before any brush actions to avoid
+ * issues with the proxies. The size of the proxy can't change, so
+ * topology must be updated first. */
+static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
+{
+ SculptSession *ss = ob->sculpt;
+ SculptSearchSphereData data;
+ PBVHNode **nodes = NULL;
+ float radius;
+ int n, totnode;
+
+ /* Build a list of all nodes that are potentially within the
+ * brush's area of influence */
+ data.ss = ss;
+ data.sd = sd;
+
+ radius = ss->cache->radius * 1.25f;
+
+ data.radius_squared = radius * radius;
+ data.original = ELEM4(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER);
+
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+
+ /* Only act if some verts are inside the brush area */
+ if (totnode) {
+ PBVHTopologyUpdateMode mode = PBVH_Subdivide;
+
+ if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) ||
+ (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY))
+ {
+ mode |= PBVH_Collapse;
+ }
+
+ for (n = 0; n < totnode; n++) {
+ sculpt_undo_push_node(ob, nodes[n],
+ brush->sculpt_tool == SCULPT_TOOL_MASK ?
+ SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ BKE_pbvh_node_mark_update(nodes[n]);
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BKE_pbvh_node_mark_topology_update(nodes[n]);
+ BKE_pbvh_bmesh_node_save_orig(nodes[n]);
+ }
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
+ ss->cache->location,
+ ss->cache->radius);
+ }
+
+ MEM_freeN(nodes);
+ }
+}
+
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
@@ -2704,7 +3015,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_LAYER);
- BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -2713,7 +3024,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
sculpt_undo_push_node(ob, nodes[n],
brush->sculpt_tool == SCULPT_TOOL_MASK ?
SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BLI_pbvh_node_mark_update(nodes[n]);
+ BKE_pbvh_node_mark_update(nodes[n]);
}
if (brush_needs_sculpt_normal(brush))
@@ -2821,7 +3132,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
PBVHNode **nodes;
int totnode, n;
- BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
/* these brushes start from original coordinates */
@@ -2833,20 +3144,27 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
PBVHVertexIter vd;
PBVHProxyNode *proxies;
int proxy_count;
- float (*orco)[3];
+ float (*orco)[3] = NULL;
- if (use_orco)
+ if (use_orco && !ss->bm)
orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co;
- BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+ BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
float val[3];
int p;
- if (use_orco)
- copy_v3_v3(val, orco[vd.i]);
+ if (use_orco) {
+ if (ss->bm) {
+ copy_v3_v3(val,
+ BM_log_original_vert_co(ss->bm_log,
+ vd.bm_vert));
+ }
+ else
+ copy_v3_v3(val, orco[vd.i]);
+ }
else
copy_v3_v3(val, vd.co);
@@ -2858,9 +3176,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
if (ss->modifiers_active)
sculpt_flush_pbvhvert_deform(ob, &vd);
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
- BLI_pbvh_node_free_proxies(nodes[n]);
+ BKE_pbvh_node_free_proxies(nodes[n]);
}
}
@@ -2877,7 +3195,7 @@ static void sculpt_update_keyblock(Object *ob)
/* Keyblock update happens after handling deformation caused by modifiers,
* so ss->orig_cos would be updated with new stroke */
if (ss->orig_cos) vertCos = ss->orig_cos;
- else vertCos = BLI_pbvh_get_vertCos(ss->pbvh);
+ else vertCos = BKE_pbvh_get_vertCos(ss->pbvh);
if (vertCos) {
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -2905,13 +3223,13 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
if (ss->kb)
vertCos = MEM_callocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
- BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_flush_pbvhvert_deform(ob, &vd);
@@ -2920,7 +3238,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
copy_v3_v3(vertCos[index], ss->orig_cos[index]);
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
if (vertCos) {
@@ -2978,7 +3296,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
}
+typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush);
+
static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
+ BrushActionFunc action,
const char symm, const int axis,
const float feather)
{
@@ -2989,7 +3310,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
ss->cache->radial_symmetry_pass = i;
calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
- do_brush_action(sd, ob, brush);
+ action(sd, ob, brush);
}
}
@@ -3006,7 +3327,8 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
multires_stitch_grids(ob);
}
-static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
+static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
+ BrushActionFunc action)
{
Brush *brush = paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
@@ -3017,7 +3339,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
float feather = calc_symmetry_feather(sd, ss->cache);
cache->bstrength = brush_strength(sd, cache, feather);
-
cache->symmetry = symm;
/* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
@@ -3027,23 +3348,13 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
cache->radial_symmetry_pass = 0;
calc_brushdata_symm(sd, cache, i, 0, 0, feather);
- do_brush_action(sd, ob, brush);
+ action(sd, ob, brush);
- do_radial_symmetry(sd, ob, brush, i, 'X', feather);
- do_radial_symmetry(sd, ob, brush, i, 'Y', feather);
- do_radial_symmetry(sd, ob, brush, i, 'Z', feather);
+ do_radial_symmetry(sd, ob, brush, action, i, 'X', feather);
+ do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather);
+ do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather);
}
}
-
- sculpt_combine_proxies(sd, ob);
-
- /* hack to fix noise texture tearing mesh */
- sculpt_fix_noise_tear(sd, ob);
-
- if (ss->modifiers_active)
- sculpt_flush_stroke_deform(sd, ob);
-
- cache->first_time = 0;
}
static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
@@ -3056,11 +3367,17 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
ss->texcache = NULL;
}
+ if (ss->tex_pool) {
+ BKE_image_pool_free(ss->tex_pool);
+ ss->tex_pool = NULL;
+ }
+
/* Need to allocate a bigger buffer for bigger brush size */
ss->texcache_side = 2 * radius;
if (!ss->texcache || ss->texcache_side > ss->texcache_actual) {
ss->texcache = BKE_brush_gen_texture_cache(brush, radius);
ss->texcache_actual = ss->texcache_side;
+ ss->tex_pool = BKE_image_pool_new();
}
}
@@ -3142,22 +3459,24 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->orig_cos = (ss->kb) ? BKE_key_convert_to_vertcos(ob, ss->kb) : mesh_getVertexCos(me, NULL);
crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
- BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
for (a = 0; a < me->totvert; ++a) {
invert_m3(ss->deform_imats[a]);
}
}
}
- else free_sculptsession_deformMats(ss);
+ else {
+ free_sculptsession_deformMats(ss);
+ }
/* if pbvh is deformed, key block is already applied to it */
- if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) {
+ if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) {
float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb);
if (vertCos) {
/* apply shape keys coordinates to PBVH */
- BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
MEM_freeN(vertCos);
}
}
@@ -3220,6 +3539,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Rotate Brush";
case SCULPT_TOOL_MASK:
return "Mask Brush";
+ case SCULPT_TOOL_SIMPLIFY:
+ return "Simplify Brush";
}
return "Sculpting";
@@ -3291,7 +3612,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
if (ss->multires) {
int i, gridsize, array_mem_size;
- BLI_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
+ BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
&gridsize, NULL, NULL);
array_mem_size = cache->num_threads * sizeof(void *);
@@ -3336,30 +3657,32 @@ static void sculpt_omp_done(SculptSession *ss)
static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
+ float rot[3][3], scale[3], loc[3];
int i;
int mode;
ss->cache = cache;
/* Set scaling adjustment */
- ss->cache->scale[0] = 1.0f / ob->size[0];
- ss->cache->scale[1] = 1.0f / ob->size[1];
- ss->cache->scale[2] = 1.0f / ob->size[2];
+ cache->scale[0] = 1.0f / ob->size[0];
+ cache->scale[1] = 1.0f / ob->size[1];
+ cache->scale[2] = 1.0f / ob->size[2];
- ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
+ cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
- ss->cache->flag = 0;
+ cache->flag = 0;
sculpt_init_mirror_clipping(ob, ss);
/* Initial mouse location */
if (mouse)
- copy_v2_v2(ss->cache->initial_mouse, mouse);
+ copy_v2_v2(cache->initial_mouse, mouse);
else
- zero_v2(ss->cache->initial_mouse);
+ zero_v2(cache->initial_mouse);
mode = RNA_enum_get(op->ptr, "mode");
cache->invert = mode == BRUSH_STROKE_INVERT;
@@ -3371,7 +3694,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
else brush->flag &= ~BRUSH_INVERTED;
/* Alt-Smooth */
- if (ss->cache->alt_smooth) {
+ if (cache->alt_smooth) {
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
cache->saved_mask_brush_tool = brush->mask_tool;
brush->mask_tool = BRUSH_MASK_SMOOTH;
@@ -3392,7 +3715,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
- copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
+ copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
/* Truly temporary data that isn't stored in properties */
@@ -3403,16 +3726,25 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* cache projection matrix */
ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
+ mat4_to_loc_rot_size(loc, rot, scale, ob->obmat);
+ /* transposing an orthonormal matrix inverts */
+ transpose_m3(rot);
ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
+ /* This takes care of rotated mesh. Instead of rotating every normal, we inverse rotate view normal. */
+ mul_m3_v3(rot, cache->true_view_normal);
/* Initialize layer brush displacements and persistent coords */
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- /* not supported yet for multires */
- if (!ss->multires && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ /* not supported yet for multires or dynamic topology */
+ if (!ss->multires && !ss->bm && !ss->layer_co &&
+ (brush->flag & BRUSH_PERSISTENT))
+ {
if (!ss->layer_co)
ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
- if (ss->deform_cos) memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ if (ss->deform_cos) {
+ memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ }
else {
for (i = 0; i < ss->totvert; ++i) {
copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
@@ -3443,8 +3775,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
}
}
- cache->special_rotation = (brush->flag & BRUSH_RAKE) ? sd->last_angle : 0;
-
cache->first_time = 1;
cache->vertex_rotation = 0;
@@ -3452,13 +3782,13 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
sculpt_omp_start(sd, ss);
}
-static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
+static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
float mouse[2] = {
- cache->mouse[0] - cache->vc->ar->winrct.xmin,
- cache->mouse[1] - cache->vc->ar->winrct.ymin
+ cache->mouse[0],
+ cache->mouse[1]
};
int tool = brush->sculpt_tool;
@@ -3478,8 +3808,6 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
/* compute 3d coordinate at same z from original location + mouse */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- initgrabz(cache->vc->rv3d, loc[0], loc[1], loc[2]);
-
ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location);
/* compute delta to move verts by */
@@ -3517,17 +3845,17 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
copy_v3_v3(cache->old_grab_location, grab_location);
if (tool == SCULPT_TOOL_GRAB)
- copy_v3_v3(sd->anchored_location, cache->true_location);
+ copy_v3_v3(cache->anchored_location, cache->true_location);
else if (tool == SCULPT_TOOL_THUMB)
- copy_v3_v3(sd->anchored_location, cache->orig_grab_location);
+ copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
- sd->draw_anchored = 1;
- copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
- sd->anchored_size = cache->pixel_radius;
+ ups->draw_anchored = 1;
+ copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
+ ups->anchored_size = ups->pixel_radius;
}
}
}
@@ -3538,6 +3866,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
@@ -3561,17 +3890,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
* brush coord/pressure/etc.
* It's more an events design issue, which doesn't split coordinate/pressure/angle
* changing events. We should avoid this after events system re-design */
- if (paint_space_stroke_enabled(brush) || cache->first_time)
+ if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) {
cache->pressure = RNA_float_get(ptr, "pressure");
+ }
/* Truly temporary data that isn't stored in properties */
-
- sd->draw_pressure = 1;
- sd->pressure_value = cache->pressure;
-
- cache->previous_pixel_radius = cache->pixel_radius;
- cache->pixel_radius = BKE_brush_size_get(scene, brush);
-
if (cache->first_time) {
if (!BKE_brush_use_locked_size(scene, brush)) {
cache->initial_radius = paint_calc_object_space_radius(cache->vc,
@@ -3584,89 +3907,37 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
}
}
- if (BKE_brush_use_size_pressure(scene, brush)) {
- cache->pixel_radius *= cache->pressure;
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) {
cache->radius = cache->initial_radius * cache->pressure;
}
- else
+ else {
cache->radius = cache->initial_radius;
+ }
cache->radius_squared = cache->radius * cache->radius;
- if (!(brush->flag & BRUSH_ANCHORED ||
- ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
- SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)))
- {
- copy_v2_v2(cache->tex_mouse, cache->mouse);
-
- if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) &&
- (brush->flag & BRUSH_RANDOM_ROTATION) &&
- !(brush->flag & BRUSH_RAKE))
- {
- cache->special_rotation = 2.0f * (float)M_PI * BLI_frand();
- }
- }
-
if (brush->flag & BRUSH_ANCHORED) {
- int hit = 0;
-
- const float dx = cache->mouse[0] - cache->initial_mouse[0];
- const float dy = cache->mouse[1] - cache->initial_mouse[1];
-
- sd->anchored_size = cache->pixel_radius = sqrt(dx * dx + dy * dy);
-
- cache->special_rotation = atan2(dx, dy) + M_PI;
-
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
float halfway[2];
float out[3];
-
- halfway[0] = dx * 0.5f + cache->initial_mouse[0];
- halfway[1] = dy * 0.5f + cache->initial_mouse[1];
+ halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]);
+ halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]);
if (sculpt_stroke_get_location(C, out, halfway)) {
- copy_v3_v3(sd->anchored_location, out);
- copy_v2_v2(sd->anchored_initial_mouse, halfway);
- copy_v2_v2(cache->tex_mouse, halfway);
- copy_v3_v3(cache->true_location, sd->anchored_location);
- sd->anchored_size /= 2.0f;
- cache->pixel_radius /= 2.0f;
- hit = 1;
+ copy_v3_v3(cache->anchored_location, out);
+ copy_v3_v3(cache->true_location, cache->anchored_location);
}
}
- if (!hit)
- copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
-
cache->radius = paint_calc_object_space_radius(paint_stroke_view_context(stroke),
cache->true_location,
- cache->pixel_radius);
+ ups->pixel_radius);
cache->radius_squared = cache->radius * cache->radius;
- copy_v3_v3(sd->anchored_location, cache->true_location);
-
- sd->draw_anchored = 1;
- }
- else if (brush->flag & BRUSH_RAKE) {
- const float u = 0.5f;
- const float v = 1 - u;
- const float r = 20;
-
- const float dx = cache->last_rake[0] - cache->mouse[0];
- const float dy = cache->last_rake[1] - cache->mouse[1];
-
- if (cache->first_time) {
- copy_v2_v2(cache->last_rake, cache->mouse);
- }
- else if (dx * dx + dy * dy >= r * r) {
- cache->special_rotation = atan2(dx, dy);
-
- cache->last_rake[0] = u * cache->last_rake[0] + v * cache->mouse[0];
- cache->last_rake[1] = u * cache->last_rake[1] + v * cache->mouse[1];
- }
+ copy_v3_v3(cache->anchored_location, cache->true_location);
}
- sculpt_update_brush_delta(sd, ob, brush);
+ sculpt_update_brush_delta(ups, ob, brush);
if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
const float dx = cache->mouse[0] - cache->initial_mouse[0];
@@ -3674,16 +3945,16 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
cache->vertex_rotation = -atan2f(dx, dy) * cache->bstrength;
- sd->draw_anchored = 1;
- copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
- copy_v3_v3(sd->anchored_location, cache->true_location);
- sd->anchored_size = cache->pixel_radius;
+ ups->draw_anchored = 1;
+ copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ ups->anchored_size = ups->pixel_radius;
}
- sd->special_rotation = cache->special_rotation;
+ cache->special_rotation = ups->brush_rotation;
}
-/* Returns true iff any of the smoothing modes are active (currently
+/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth) */
static int sculpt_any_smooth_mode(const Brush *brush,
@@ -3721,17 +3992,26 @@ typedef struct {
static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{
- if (BLI_pbvh_node_get_tmin(node) < *tmin) {
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
SculptRaycastData *srd = data_v;
float (*origco)[3] = NULL;
+ int use_origco = FALSE;
if (srd->original && srd->ss->cache) {
- /* intersect with coordinates from before we started stroke */
- SculptUndoNode *unode = sculpt_undo_get_node(node);
- origco = (unode) ? unode->co : NULL;
+ if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ use_origco = TRUE;
+ }
+ else {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode = sculpt_undo_get_node(node);
+ origco = (unode) ? unode->co : NULL;
+ use_origco = origco ? TRUE : FALSE;
+ }
}
- if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) {
+ if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco,
+ srd->ray_start, srd->ray_normal, &srd->dist))
+ {
srd->hit = 1;
*tmin = srd->dist;
}
@@ -3750,7 +4030,6 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
StrokeCache *cache;
float ray_start[3], ray_end[3], ray_normal[3], dist;
float obimat[4][4];
- float mval[2];
SculptRaycastData srd;
view3d_set_viewcontext(C, &vc);
@@ -3761,11 +4040,8 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
sculpt_stroke_modifiers_check(C, ob);
- mval[0] = mouse[0] - vc.ar->winrct.xmin;
- mval[1] = mouse[1] - vc.ar->winrct.ymin;
-
/* TODO: what if the segment is totally clipped? (return == 0) */
- ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mval, ray_start, ray_end);
+ ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mouse, ray_start, ray_end);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
@@ -3780,7 +4056,7 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
srd.dist = dist;
srd.hit = 0;
srd.original = (cache) ? cache->original : 0;
- BLI_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
+ BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
ray_start, ray_normal, srd.original);
copy_v3_v3(out, ray_normal);
@@ -3797,7 +4073,7 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession
/* init mtex nodes */
if (mtex->tex && mtex->tex->nodetree)
- ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */
+ ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */
/* TODO: Shouldn't really have to do this at the start of every
* stroke, but sculpt would need some sort of notification when
@@ -3829,8 +4105,9 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
return 1;
}
-static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
+static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
/* Restore the mesh before continuing with anchored stroke */
@@ -3839,7 +4116,18 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
(brush->flag & BRUSH_RESTORE_MESH))
{
- paint_mesh_restore_co(sd, ss);
+ paint_mesh_restore_co(sd, ob);
+ }
+}
+
+/* Copy the PBVH bounding box into the object's bounding box */
+static void sculpt_update_object_bounding_box(Object *ob)
+{
+ if (ob->bb) {
+ float bb_min[3], bb_max[3];
+
+ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
+ BKE_boundbox_init_from_minmax(ob->bb, bb_min, bb_max);
}
}
@@ -3862,7 +4150,12 @@ static void sculpt_flush_update(bContext *C)
else {
rcti r;
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+ /* Update the object's bounding box too so that the object
+ * doesn't get incorrectly clipped during drawing in
+ * draw_mesh_object(). [#33790] */
+ sculpt_update_object_bounding_box(ob);
+
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
if (ss->cache)
ss->cache->previous_r = r;
@@ -3914,14 +4207,37 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ const Brush *brush = paint_brush(&sd->paint);
sculpt_stroke_modifiers_check(C, ob);
sculpt_update_cache_variants(C, sd, ob, stroke, itemptr);
- sculpt_restore_mesh(sd, ss);
- do_symmetrical_brush_actions(sd, ob);
+ sculpt_restore_mesh(sd, ob);
+
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
+ (ss->cache->radius /
+ (float)ups->pixel_radius) *
+ (float)sd->detail_size);
+
+ if (sculpt_stroke_dynamic_topology(ss, brush)) {
+ do_symmetrical_brush_actions(sd, ob, sculpt_topology_update);
+ }
+
+ if (paint_brush(&sd->paint)->sculpt_tool != SCULPT_TOOL_SIMPLIFY)
+ do_symmetrical_brush_actions(sd, ob, do_brush_action);
+
+ sculpt_combine_proxies(sd, ob);
+
+ /* hack to fix noise texture tearing mesh */
+ sculpt_fix_noise_tear(sd, ob);
+
+ if (ss->modifiers_active)
+ sculpt_flush_stroke_deform(sd, ob);
+
+ ss->cache->first_time = FALSE;
/* Cleanup */
sculpt_flush_update(C);
@@ -3933,11 +4249,12 @@ static void sculpt_brush_exit_tex(Sculpt *sd)
MTex *mtex = &brush->mtex;
if (mtex->tex && mtex->tex->nodetree)
- ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1);
+ ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
}
static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
{
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -3945,9 +4262,8 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_omp_done(ss);
/* reset values used to draw brush after completing the stroke */
- sd->draw_anchored = 0;
- sd->draw_pressure = 0;
- sd->special_rotation = 0;
+ ups->draw_anchored = 0;
+ ups->draw_pressure = 0;
/* Finished */
if (ss->cache) {
@@ -3980,7 +4296,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_undo_push_end();
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)
+ BKE_pbvh_bmesh_after_stroke(ss->pbvh);
/* optimization: if there is locked key and active modifiers present in */
/* the stack, keyblock is updating at each step. otherwise we could update */
@@ -3999,7 +4318,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_brush_exit_tex(sd);
}
-static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
struct PaintStroke *stroke;
int ignore_background_click;
@@ -4016,8 +4335,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
op->customdata = stroke;
/* For tablet rotation */
- ignore_background_click = RNA_boolean_get(op->ptr,
- "ignore_background_click");
+ ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
paint_stroke_data_free(op);
@@ -4055,7 +4373,7 @@ static int sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
if (ss->cache) {
- paint_mesh_restore_co(sd, ss);
+ paint_mesh_restore_co(sd, ob);
}
paint_stroke_cancel(C, op);
@@ -4096,8 +4414,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* properties */
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement,
- "Stroke", "");
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
"Sculpt Stroke Mode",
@@ -4137,6 +4454,265 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/************************** Dynamic Topology **************************/
+
+static void sculpt_dynamic_topology_triangulate(BMesh *bm)
+{
+ BM_mesh_triangulate(bm, false, false, NULL, NULL);
+}
+
+void sculpt_pbvh_clear(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ DerivedMesh *dm = ob->derivedFinal;
+
+ /* Clear out any existing DM and PBVH */
+ if (ss->pbvh)
+ BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ if (dm)
+ dm->getPBVH(NULL, dm);
+ BKE_object_free_display(ob);
+}
+
+void sculpt_update_after_dynamic_topology_toggle(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Sculpt *sd = scene->toolsettings->sculpt;
+
+ /* Create the PBVH */
+ sculpt_update_mesh_elements(scene, sd, ob, FALSE, FALSE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+}
+
+void sculpt_dynamic_topology_enable(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ sculpt_pbvh_clear(ob);
+
+ ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags &
+ SCULPT_DYNTOPO_SMOOTH_SHADING);
+
+ /* Create triangles-only BMesh */
+ ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+
+ BM_mesh_bm_from_me(ss->bm, me, TRUE, ob->shapenr);
+ BM_mesh_normals_update(ss->bm, false);
+ sculpt_dynamic_topology_triangulate(ss->bm);
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ BM_mesh_normals_update(ss->bm, TRUE);
+
+ /* Enable dynamic topology */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Enable logging for undo/redo */
+ ss->bm_log = BM_log_create(ss->bm);
+
+ /* Refresh */
+ sculpt_update_after_dynamic_topology_toggle(C);
+}
+
+/* Free the sculpt BMesh and BMLog
+ *
+ * If 'unode' is given, the BMesh's data is copied out to the unode
+ * before the BMesh is deleted so that it can be restored from */
+void sculpt_dynamic_topology_disable(bContext *C,
+ SculptUndoNode *unode)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ sculpt_pbvh_clear(ob);
+
+ if (unode) {
+ /* Free all existing custom data */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* Copy over stored custom data */
+ me->totvert = unode->bm_enter_totvert;
+ me->totloop = unode->bm_enter_totloop;
+ me->totpoly = unode->bm_enter_totpoly;
+ me->totedge = unode->bm_enter_totedge;
+ me->totface = 0;
+ CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totvert);
+ CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totedge);
+ CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totloop);
+ CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totpoly);
+
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
+ else {
+ sculptsession_bm_to_me(ob, TRUE);
+ }
+
+ BM_mesh_free(ss->bm);
+
+ /* Clear data */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ ss->bm = NULL;
+ BM_log_free(ss->bm_log);
+ ss->bm_log = NULL;
+
+ /* Refresh */
+ sculpt_update_after_dynamic_topology_toggle(C);
+}
+
+static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->bm) {
+ sculpt_undo_push_begin("Dynamic topology disable");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
+ sculpt_dynamic_topology_disable(C, NULL);
+ }
+ else {
+ sculpt_undo_push_begin("Dynamic topology enable");
+ sculpt_dynamic_topology_enable(C);
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ }
+ sculpt_undo_push_end();
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+ const char *msg = TIP_("Dynamic-topology sculpting will not preserve vertex colors, UVs, or other customdata");
+
+ if (!ss->bm) {
+ int i;
+
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
+ (CustomData_has_layer(&me->vdata, i) ||
+ CustomData_has_layer(&me->edata, i) ||
+ CustomData_has_layer(&me->fdata, i)))
+ {
+ /* The mesh has customdata that will be lost, let the user confirm this is OK */
+ return WM_operator_confirm_message(C, op, msg);
+ }
+ }
+ }
+
+ return sculpt_dynamic_topology_toggle_exec(C, op);
+}
+
+static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dynamic Topology Toggle";
+ ot->idname = "SCULPT_OT_dynamic_topology_toggle";
+ ot->description = "Dynamic topology alters the mesh topology while sculpting";
+
+ /* api callbacks */
+ ot->invoke = sculpt_dynamic_topology_toggle_invoke;
+ ot->exec = sculpt_dynamic_topology_toggle_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ sculpt_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_and_dynamic_topology_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return sculpt_mode_poll(C) && ob->sculpt->bm;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Optimize";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
+
+ /* api callbacks */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies) */
+ sculpt_undo_push_begin("Dynamic topology symmetrize");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+ /* Symmetrize and re-triangulate */
+ BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS,
+ "symmetrize input=%avef direction=%i",
+ sd->symmetrize_direction);
+ sculpt_dynamic_topology_triangulate(ss->bm);
+
+ /* Finish undo */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ sculpt_undo_push_end();
+
+ /* Redraw */
+ sculpt_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
+
+ /* api callbacks */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+}
+
/**** Toggle operator for turning sculpt mode on or off ****/
static void sculpt_init_session(Scene *scene, Object *ob)
@@ -4222,6 +4798,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
int flush_recalc = 0;
@@ -4234,9 +4811,16 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
if (mmd)
multires_force_update(ob);
- if (flush_recalc)
+ if (flush_recalc || (ob->sculpt && ob->sculpt->bm))
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state */
+ sculpt_dynamic_topology_toggle_exec(C, NULL);
+ }
+
/* Leave sculptmode */
ob->mode &= ~OB_MODE_SCULPT;
@@ -4246,6 +4830,12 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
/* Enter sculptmode */
ob->mode |= OB_MODE_SCULPT;
+ /* Remove dynamic-topology flag; this will be enabled if the
+ * file was saved with dynamic topology on, but we don't
+ * automatically re-enter dynamic-topology mode when loading a
+ * file. */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+
if (flush_recalc)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -4257,6 +4847,9 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
ts->sculpt->flags |= SCULPT_SYMM_X;
}
+ if (!ts->sculpt->detail_size)
+ ts->sculpt->detail_size = 30;
+
/* Create sculpt mode session data */
if (ob->sculpt)
free_sculptsession(ob);
@@ -4271,7 +4864,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
}
BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
-
+
paint_cursor_start(C, sculpt_poll);
}
@@ -4299,4 +4892,7 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_brush_stroke);
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
}