diff options
Diffstat (limited to 'source/blender/blenkernel/intern/paint.cc')
-rw-r--r-- | source/blender/blenkernel/intern/paint.cc | 883 |
1 files changed, 703 insertions, 180 deletions
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 1a1bf285847..a39e53662aa 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -25,6 +25,7 @@ #include "BLI_hash.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_string_utf8.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -41,6 +42,7 @@ #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" @@ -52,6 +54,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_scene.h" #include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" @@ -64,6 +67,16 @@ #include "bmesh.h" +static void sculpt_attribute_update_refs(Object *ob); +static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params, + PBVHType pbvhtype, + bool flat_array_for_bmesh); +void sculptsession_bmesh_add_layers(Object *ob); + using blender::MutableSpan; using blender::Span; @@ -77,10 +90,7 @@ static void palette_init_data(ID *id) id_fake_user_set(&palette->id); } -static void palette_copy_data(Main *UNUSED(bmain), - ID *id_dst, - const ID *id_src, - const int UNUSED(flag)) +static void palette_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/) { Palette *palette_dst = (Palette *)id_dst; const Palette *palette_src = (const Palette *)id_src; @@ -111,7 +121,7 @@ static void palette_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_list(reader, &palette->colors); } -static void palette_undo_preserve(BlendLibReader *UNUSED(reader), ID *id_new, ID *id_old) +static void palette_undo_preserve(BlendLibReader * /*reader*/, ID *id_new, ID *id_old) { /* Whole Palette is preserved across undo-steps, and it has no extra pointer, simple. */ /* NOTE: We do not care about potential internal references to self here, Palette has none. */ @@ -151,10 +161,10 @@ IDTypeInfo IDType_ID_PAL = { /* lib_override_apply_post */ nullptr, }; -static void paint_curve_copy_data(Main *UNUSED(bmain), +static void paint_curve_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, - const int UNUSED(flag)) + const int /*flag*/) { PaintCurve *paint_curve_dst = (PaintCurve *)id_dst; const PaintCurve *paint_curve_src = (const PaintCurve *)id_src; @@ -447,9 +457,11 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) { if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; + BKE_view_layer_synced_ensure(sce, view_layer); + Object *actob = BKE_view_layer_active_object_get(view_layer); - if (view_layer->basact && view_layer->basact->object) { - switch (view_layer->basact->object->mode) { + if (actob) { + switch (actob->mode) { case OB_MODE_SCULPT: return &ts->sculpt->paint; case OB_MODE_VERTEX_PAINT: @@ -490,11 +502,8 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; - Object *obact = nullptr; - - if (view_layer->basact && view_layer->basact->object) { - obact = view_layer->basact->object; - } + BKE_view_layer_synced_ensure(sce, view_layer); + Object *obact = BKE_view_layer_active_object_get(view_layer); if ((sima = CTX_wm_space_image(C)) != nullptr) { if (obact && obact->mode == OB_MODE_EDIT) { @@ -524,11 +533,8 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) SpaceImage *sima; if (sce && view_layer) { - Object *obact = nullptr; - - if (view_layer->basact && view_layer->basact->object) { - obact = view_layer->basact->object; - } + BKE_view_layer_synced_ensure(sce, view_layer); + Object *obact = BKE_view_layer_active_object_get(view_layer); if ((sima = CTX_wm_space_image(C)) != nullptr) { if (obact && obact->mode == OB_MODE_EDIT) { @@ -1037,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) return OB_MODE_TEXTURE_PAINT; case PAINT_MODE_SCULPT_UV: return OB_MODE_EDIT; + case PAINT_MODE_SCULPT_CURVES: + return OB_MODE_SCULPT_CURVES; case PAINT_MODE_INVALID: default: return OB_MODE_OBJECT; @@ -1193,7 +1201,7 @@ void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) mul_v3_v3fl(stroke, ups->average_stroke_accum, fac); } else { - copy_v3_v3(stroke, ob->obmat[3]); + copy_v3_v3(stroke, ob->object_to_world[3]); } } @@ -1307,13 +1315,22 @@ void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, f } } +static bool paint_rake_rotation_active(const MTex &mtex) +{ + return mtex.tex && mtex.brush_angle_mode & MTEX_ANGLE_RAKE; +} + +static bool paint_rake_rotation_active(const Brush &brush) +{ + return paint_rake_rotation_active(brush.mtex) || paint_rake_rotation_active(brush.mask_mtex); +} + bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) { bool ok = false; - if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || - (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { + if (paint_rake_rotation_active(*brush)) { const float r = RAKE_THRESHHOLD; float rotation; @@ -1433,13 +1450,9 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->vemap); MEM_SAFE_FREE(ss->vemap_mem); - MEM_SAFE_FREE(ss->persistent_base); - MEM_SAFE_FREE(ss->preview_vert_list); ss->preview_vert_count = 0; - MEM_SAFE_FREE(ss->preview_vert_list); - MEM_SAFE_FREE(ss->vertex_info.connected_component); MEM_SAFE_FREE(ss->vertex_info.boundary); @@ -1473,6 +1486,8 @@ void BKE_sculptsession_free(Object *ob) if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; + BKE_sculpt_attribute_destroy_temporary_all(ob); + if (ss->bm) { BKE_sculptsession_bm_to_me(ob, true); BM_mesh_free(ss->bm); @@ -1547,9 +1562,7 @@ static MultiresModifierData *sculpt_multires_modifier_get(const Scene *scene, /* Multires can't work without displacement layer. */ return nullptr; } - else { - need_mdisps = true; - } + need_mdisps = true; } /* Weight paint operates on original vertices, and needs to treat multires as regular modifier @@ -1631,6 +1644,21 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) return false; } +/* Helper function to keep persistent base attribute references up to + * date. This is a bit more tricky since they persist across strokes. + */ +static void sculpt_update_persistent_base(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + ss->attrs.persistent_co = BKE_sculpt_attribute_get( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_co)); + ss->attrs.persistent_no = BKE_sculpt_attribute_get( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_no)); + ss->attrs.persistent_disp = BKE_sculpt_attribute_get( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(persistent_disp)); +} + static void sculpt_update_object( Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool) { @@ -1709,13 +1737,16 @@ static void sculpt_update_object( /* Sculpt Face Sets. */ if (use_face_sets) { - ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS)); + ss->face_sets = static_cast<int *>( + CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set")); } else { ss->face_sets = nullptr; } - ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; + ss->hide_poly = (bool *)CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly"); + + ss->subdiv_ccg = me_eval->runtime->subdiv_ccg; PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); BLI_assert(pbvh == ss->pbvh); @@ -1723,9 +1754,13 @@ static void sculpt_update_object( BKE_pbvh_subdiv_cgg_set(ss->pbvh, ss->subdiv_ccg); BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets); + BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh); BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default); + sculpt_attribute_update_refs(ob); + sculpt_update_persistent_base(ob); + if (need_pmap && ob->type == OB_MESH && !ss->pmap) { BKE_mesh_vert_poly_map_create(&ss->pmap, &ss->pmap_mem, @@ -1753,14 +1788,14 @@ static void sculpt_update_object( /* If the fully evaluated mesh has the same topology as the deform-only version, use it. * This matters because crazyspace evaluation is very restrictive and excludes even modifiers * that simply recompute vertex weights (which can even include Geometry Nodes). */ - if (me_eval_deform->polys().data() == me_eval->polys().data() && - me_eval_deform->loops().data() == me_eval->loops().data() && + if (me_eval_deform->totpoly == me_eval->totpoly && + me_eval_deform->totloop == me_eval->totloop && me_eval_deform->totvert == me_eval->totvert) { BKE_sculptsession_free_deformMats(ss); BLI_assert(me_eval_deform->totvert == me->totvert); - ss->deform_cos = BKE_mesh_vert_coords_alloc(me_eval, NULL); + ss->deform_cos = BKE_mesh_vert_coords_alloc(me_eval, nullptr); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert); used_me_eval = true; @@ -1930,43 +1965,34 @@ int *BKE_sculpt_face_sets_ensure(Mesh *mesh) { using namespace blender; using namespace blender::bke; - if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { - return static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); + MutableAttributeAccessor attributes = mesh->attributes_for_write(); + if (!attributes.contains(".sculpt_face_set")) { + SpanAttributeWriter<int> face_sets = attributes.lookup_or_add_for_write_only_span<int>( + ".sculpt_face_set", ATTR_DOMAIN_FACE); + face_sets.span.fill(1); + mesh->face_sets_color_default = 1; + face_sets.finish(); } - const AttributeAccessor attributes = mesh->attributes_for_write(); - const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( - ".hide_poly", ATTR_DOMAIN_FACE, false); - - MutableSpan<int> face_sets = { - static_cast<int *>(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)), - mesh->totpoly}; - - /* Initialize the new face sets with a default valid visible ID and set the default - * color to render it white. */ - if (hide_poly.is_single() && !hide_poly.get_internal_single()) { - face_sets.fill(1); - } - else { - const int face_sets_default_visible_id = 1; - const int face_sets_default_hidden_id = -2; + return static_cast<int *>( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, ".sculpt_face_set")); +} - const VArraySpan<bool> hide_poly_span{hide_poly}; - for (const int i : face_sets.index_range()) { - /* Assign a new hidden ID to hidden faces. This way we get at initial split in two Face Sets - * between hidden and visible faces based on the previous mesh visibly from other mode that - * can be useful in some cases. */ - face_sets[i] = hide_poly_span[i] ? face_sets_default_hidden_id : - face_sets_default_visible_id; - } +bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh) +{ + bool *hide_poly = static_cast<bool *>( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly")); + if (hide_poly != nullptr) { + return hide_poly; } - - mesh->face_sets_color_default = 1; - return face_sets.data(); + return static_cast<bool *>(CustomData_add_layer_named( + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly")); } -int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) +int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, + Main *bmain, + Object *ob, + MultiresModifierData *mmd) { Mesh *me = static_cast<Mesh *>(ob->data); const Span<MPoly> polys = me->polys(); @@ -2007,7 +2033,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) const MLoop *l = &loops[p->loopstart + j]; avg += paint_mask[l->v]; } - avg /= (float)p->totloop; + avg /= float(p->totloop); /* fill in multires mask corner */ for (j = 0; j < p->totloop; j++) { @@ -2023,6 +2049,11 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) } } } + /* The evaluated multires CCG must be updated to contain the new data. */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + if (depsgraph) { + BKE_scene_graph_evaluated_ensure(depsgraph, bmain); + } ret |= SCULPT_MASK_LAYER_CALC_LOOP; } @@ -2030,6 +2061,8 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) /* Create vertex paint mask layer if there isn't one already. */ if (!paint_mask) { CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totvert); + /* The evaluated mesh must be updated to contain the new data. */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); ret |= SCULPT_MASK_LAYER_CALC_VERT; } @@ -2051,6 +2084,14 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene) sd->constant_detail = 3.0f; } + if (!sd->automasking_start_normal_limit) { + sd->automasking_start_normal_limit = 20.0f / 180.0f * M_PI; + sd->automasking_start_normal_falloff = 0.25f; + + sd->automasking_view_normal_limit = 90.0f / 180.0f * M_PI; + sd->automasking_view_normal_falloff = 0.25f; + } + /* Set sane default tiling offsets. */ if (!sd->paint.tile_offset[0]) { sd->paint.tile_offset[0] = 1.0f; @@ -2061,6 +2102,9 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene) if (!sd->paint.tile_offset[2]) { sd->paint.tile_offset[2] = 1.0f; } + if (!sd->automasking_cavity_curve || !sd->automasking_cavity_curve_op) { + BKE_sculpt_check_cavity_curves(sd); + } } static bool check_sculpt_object_deformed(Object *object, const bool for_construction) @@ -2085,11 +2129,11 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc return deformed; } -void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh) +void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) { using namespace blender; using namespace blender::bke; - if (!CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { + if (!subdiv_ccg) { return; } @@ -2097,70 +2141,19 @@ void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh) const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( ".hide_poly", ATTR_DOMAIN_FACE, false); if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + /* Nothing is hidden, so we can just remove all visibility bitmaps. */ + for (const int i : IndexRange(subdiv_ccg->num_grids)) { + BKE_subdiv_ccg_grid_hidden_free(subdiv_ccg, i); + } return; } - MutableSpan<int> face_sets{ - static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)), mesh->totpoly}; - - for (const int i : hide_poly.index_range()) { - face_sets[i] = hide_poly[i] ? -std::abs(face_sets[i]) : std::abs(face_sets[i]); - } -} - -static void set_hide_poly_from_face_sets(Mesh &mesh) -{ - using namespace blender; - using namespace blender::bke; - if (!CustomData_has_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)) { - return; - } - - const Span<int> face_sets{ - static_cast<const int *>(CustomData_get_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)), - mesh.totpoly}; - - MutableAttributeAccessor attributes = mesh.attributes_for_write(); - if (std::all_of( - face_sets.begin(), face_sets.end(), [&](const int value) { return value > 0; })) { - attributes.remove(".hide_poly"); - return; - } - - SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( - ".hide_poly", ATTR_DOMAIN_FACE); - if (!hide_poly) { - return; - } - for (const int i : hide_poly.span.index_range()) { - hide_poly.span[i] = face_sets[i] < 0; - } - hide_poly.finish(); -} - -void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) -{ - set_hide_poly_from_face_sets(*mesh); - BKE_mesh_flush_hidden_from_polys(mesh); -} - -void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) -{ - const int *face_sets = static_cast<const int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - if (!face_sets) { - return; - } - - if (!subdiv_ccg) { - return; - } - + const VArraySpan<bool> hide_poly_span(hide_poly); CCGKey key; BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); for (int i = 0; i < mesh->totloop; i++) { const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, i); - const bool is_hidden = (face_sets[face_index] < 0); + const bool is_hidden = hide_poly_span[face_index]; /* Avoid creating and modifying the grid_hidden bitmap if the base mesh face is visible and * there is not bitmap for the grid. This is because missing grid_hidden implies grid is fully @@ -2176,50 +2169,18 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv } } -void BKE_sculpt_sync_face_set_visibility(Mesh *mesh, SubdivCCG *subdiv_ccg) -{ - BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh); - BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh); - BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg); -} - -void BKE_sculpt_ensure_orig_mesh_data(Object *object) +static PBVH *build_pbvh_for_dynamic_topology(Object *ob) { - Mesh *mesh = BKE_mesh_from_object(object); - BLI_assert(object->mode == OB_MODE_SCULPT); - - /* Copy the current mesh visibility to the Face Sets. */ - BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh); + PBVH *pbvh = ob->sculpt->pbvh = BKE_pbvh_new(PBVH_BMESH); - /* Tessfaces aren't used and will become invalid. */ - BKE_mesh_tessface_clear(mesh); + sculptsession_bmesh_add_layers(ob); - /* We always need to flush updates from depsgraph here, since at the very least - * `BKE_sculpt_face_sets_update_from_base_mesh_visibility()` will have updated some data layer of - * the mesh. - * - * All known potential sources of updates: - * - Addition of, or changes to, the `CD_SCULPT_FACE_SETS` data layer - * (`BKE_sculpt_face_sets_update_from_base_mesh_visibility`). - * - Addition of a `CD_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`). - * - Object has any active modifier (modifier stack can be different in Sculpt mode). - * - Multires: - * + Differences of subdiv levels between sculpt and object modes - * (`mmd->sculptlvl != mmd->lvl`). - * + Addition of a `CD_GRID_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`). - */ - DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); -} - -static PBVH *build_pbvh_for_dynamic_topology(Object *ob) -{ - PBVH *pbvh = BKE_pbvh_new(); BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm, ob->sculpt->bm_smooth_shading, ob->sculpt->bm_log, - ob->sculpt->cd_vert_node_offset, - ob->sculpt->cd_face_node_offset); + ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset, + ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, false); return pbvh; @@ -2229,7 +2190,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool { Mesh *me = BKE_object_get_original_mesh(ob); const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); - PBVH *pbvh = BKE_pbvh_new(); + PBVH *pbvh = BKE_pbvh_new(PBVH_FACES); BKE_pbvh_respect_hide_set(pbvh, respect_hide); MutableSpan<MVert> verts = me->verts_for_write(); @@ -2242,8 +2203,6 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool BKE_mesh_recalc_looptri( loops.data(), polys.data(), verts.data(), me->totloop, me->totpoly, looptri); - BKE_sculpt_sync_face_set_visibility(me, nullptr); - BKE_pbvh_build_mesh(pbvh, me, polys.data(), @@ -2274,11 +2233,11 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect { CCGKey key; BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); - PBVH *pbvh = BKE_pbvh_new(); + PBVH *pbvh = BKE_pbvh_new(PBVH_GRIDS); BKE_pbvh_respect_hide_set(pbvh, respect_hide); Mesh *base_mesh = BKE_mesh_from_object(ob); - BKE_sculpt_sync_face_set_visibility(base_mesh, subdiv_ccg); + BKE_sculpt_sync_face_visibility_to_grids(base_mesh, subdiv_ccg); BKE_pbvh_build_grids(pbvh, subdiv_ccg->grids, @@ -2286,7 +2245,9 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect &key, (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, - subdiv_ccg->grid_hidden); + subdiv_ccg->grid_hidden, + base_mesh, + subdiv_ccg); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); return pbvh; @@ -2307,7 +2268,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); - SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; + SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg; if (subdiv_ccg != nullptr) { BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg); } @@ -2326,8 +2287,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) else { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); - if (mesh_eval->runtime.subdiv_ccg != nullptr) { - pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide); + if (mesh_eval->runtime->subdiv_ccg != nullptr) { + pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg, respect_hide); } else if (ob->type == OB_MESH) { Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval; @@ -2336,21 +2297,26 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) } BKE_pbvh_pmap_set(pbvh, ob->sculpt->pmap); - ob->sculpt->pbvh = pbvh; + + sculpt_attribute_update_refs(ob); return pbvh; } void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg) { + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + BKE_pbvh_grids_update(pbvh, subdiv_ccg->grids, (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, - subdiv_ccg->grid_hidden); + subdiv_ccg->grid_hidden, + &key); } -bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d)) +bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d) { SculptSession *ss = ob->sculpt; if (ss == nullptr || ss->pbvh == nullptr || ss->mode_type != OB_MODE_SCULPT) { @@ -2358,9 +2324,10 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d) } if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - /* Regular mesh only draws from PBVH without modifiers and shape keys. */ - - return !(ss->shapekey_active || ss->deform_modifiers_active); + /* Regular mesh only draws from PBVH without modifiers and shape keys, or for + * external engines that do not have access to the PBVH like Eevee does. */ + const bool external_engine = rv3d && rv3d->render_engine != nullptr; + return !(ss->shapekey_active || ss->deform_modifiers_active || external_engine); } /* Multires and dyntopo always draw directly from the PBVH. */ @@ -2372,10 +2339,10 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d) void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uchar r_color[4]) { float rgba[4]; - float random_mod_hue = GOLDEN_RATIO_CONJUGATE * (abs(face_set) + (seed % 10)); + float random_mod_hue = GOLDEN_RATIO_CONJUGATE * (face_set + (seed % 10)); random_mod_hue = random_mod_hue - floorf(random_mod_hue); - const float random_mod_sat = BLI_hash_int_01(abs(face_set) + seed + 1); - const float random_mod_val = BLI_hash_int_01(abs(face_set) + seed + 2); + const float random_mod_sat = BLI_hash_int_01(face_set + seed + 1); + const float random_mod_val = BLI_hash_int_01(face_set + seed + 2); hsv_to_rgb(random_mod_hue, 0.6f + (random_mod_sat * 0.25f), 1.0f - (random_mod_val * 0.35f), @@ -2384,3 +2351,559 @@ void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uc &rgba[2]); rgba_float_to_uchar(r_color, rgba); } + +int BKE_sculptsession_vertex_count(const SculptSession *ss) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return ss->totvert; + case PBVH_BMESH: + return BM_mesh_elem_count(ss->bm, BM_VERT); + case PBVH_GRIDS: + return BKE_pbvh_get_grid_num_verts(ss->pbvh); + } + + return 0; +} + +/** Returns pointer to a CustomData associated with a given domain, if + * one exists. If not nullptr is returned (this may happen with e.g. + * multires and ATTR_DOMAIN_POINT). + */ +static CustomData *sculpt_get_cdata(Object *ob, eAttrDomain domain) +{ + SculptSession *ss = ob->sculpt; + + if (ss->bm) { + switch (domain) { + case ATTR_DOMAIN_POINT: + return &ss->bm->vdata; + case ATTR_DOMAIN_FACE: + return &ss->bm->pdata; + default: + BLI_assert_unreachable(); + return nullptr; + } + } + else { + Mesh *me = BKE_object_get_original_mesh(ob); + + switch (domain) { + case ATTR_DOMAIN_POINT: + /* Cannot get vertex domain for multires grids. */ + if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + return nullptr; + } + + return &me->vdata; + case ATTR_DOMAIN_FACE: + return &me->pdata; + default: + BLI_assert_unreachable(); + return nullptr; + } + } +} + +static int sculpt_attr_elem_count_get(Object *ob, eAttrDomain domain) +{ + SculptSession *ss = ob->sculpt; + + switch (domain) { + case ATTR_DOMAIN_POINT: + return BKE_sculptsession_vertex_count(ss); + break; + case ATTR_DOMAIN_FACE: + return ss->totfaces; + break; + default: + BLI_assert_unreachable(); + return 0; + } +} + +static bool sculpt_attribute_create(SculptSession *ss, + Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + SculptAttribute *out, + const SculptAttributeParams *params, + PBVHType pbvhtype, + bool flat_array_for_bmesh) +{ + Mesh *me = BKE_object_get_original_mesh(ob); + + bool simple_array = params->simple_array; + bool permanent = params->permanent; + + out->params = *params; + out->proptype = proptype; + out->domain = domain; + BLI_strncpy_utf8(out->name, name, sizeof(out->name)); + + /* Force non-CustomData simple_array mode if not PBVH_FACES. */ + if (pbvhtype == PBVH_GRIDS || (pbvhtype == PBVH_BMESH && flat_array_for_bmesh)) { + if (permanent) { + printf( + "%s: error: tried to make permanent customdata in multires or bmesh mode; will make " + "local " + "array " + "instead.\n", + __func__); + permanent = (out->params.permanent = false); + } + + simple_array = (out->params.simple_array = true); + } + + BLI_assert(!(simple_array && permanent)); + + int totelem = sculpt_attr_elem_count_get(ob, domain); + + if (simple_array) { + int elemsize = CustomData_sizeof(proptype); + + out->data = MEM_calloc_arrayN(totelem, elemsize, __func__); + + out->data_for_bmesh = ss->bm != nullptr; + out->bmesh_cd_offset = -1; + out->layer = nullptr; + out->elem_size = elemsize; + out->used = true; + out->elem_num = totelem; + + return true; + } + + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_BMESH: { + CustomData *cdata = nullptr; + out->data_for_bmesh = true; + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = &ss->bm->vdata; + break; + case ATTR_DOMAIN_FACE: + cdata = &ss->bm->pdata; + break; + default: + out->used = false; + return false; + } + + BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1); + + BM_data_layer_add_named(ss->bm, cdata, proptype, name); + int index = CustomData_get_named_layer_index(cdata, proptype, name); + + if (!permanent) { + cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY; + } + + out->data = nullptr; + out->layer = cdata->layers + index; + out->bmesh_cd_offset = out->layer->offset; + out->elem_size = CustomData_sizeof(proptype); + break; + } + case PBVH_FACES: { + CustomData *cdata = nullptr; + + out->data_for_bmesh = false; + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = &me->vdata; + break; + case ATTR_DOMAIN_FACE: + cdata = &me->pdata; + break; + default: + out->used = false; + return false; + } + + BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1); + + CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, nullptr, totelem, name); + int index = CustomData_get_named_layer_index(cdata, proptype, name); + + if (!permanent) { + cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY; + } + + out->data = nullptr; + out->layer = cdata->layers + index; + out->bmesh_cd_offset = -1; + out->data = out->layer->data; + out->elem_size = CustomData_get_elem_size(out->layer); + + break; + } + case PBVH_GRIDS: { + /* GRIDS should have been handled as simple arrays. */ + BLI_assert_unreachable(); + break; + } + default: + BLI_assert_unreachable(); + break; + } + + out->used = true; + out->elem_num = totelem; + + return true; +} + +static bool sculpt_attr_update(Object *ob, SculptAttribute *attr) +{ + SculptSession *ss = ob->sculpt; + int elem_num = sculpt_attr_elem_count_get(ob, attr->domain); + + bool bad = false; + + if (attr->params.simple_array) { + bad = attr->elem_num != elem_num; + + if (bad) { + MEM_SAFE_FREE(attr->data); + } + } + else { + CustomData *cdata = sculpt_get_cdata(ob, attr->domain); + + if (cdata) { + int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name); + bad = layer_index == -1; + + if (ss->bm) { + attr->bmesh_cd_offset = cdata->layers[layer_index].offset; + } + } + } + + if (bad) { + sculpt_attribute_create(ss, + ob, + attr->domain, + attr->proptype, + attr->name, + attr, + &attr->params, + BKE_pbvh_type(ss->pbvh), + true); + } + + return bad; +} + +static SculptAttribute *sculpt_get_cached_layer(SculptSession *ss, + eAttrDomain domain, + eCustomDataType proptype, + const char *name) +{ + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr = ss->temp_attributes + i; + + if (attr->used && STREQ(attr->name, name) && attr->proptype == proptype && + attr->domain == domain) { + + return attr; + } + } + + return nullptr; +} + +bool BKE_sculpt_attribute_exists(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name) +{ + SculptSession *ss = ob->sculpt; + SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name); + + if (attr) { + return true; + } + + CustomData *cdata = sculpt_get_cdata(ob, domain); + return CustomData_get_named_layer_index(cdata, proptype, name) != -1; + + return false; +} + +static SculptAttribute *sculpt_alloc_attr(SculptSession *ss) +{ + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + if (!ss->temp_attributes[i].used) { + memset((void *)(ss->temp_attributes + i), 0, sizeof(SculptAttribute)); + ss->temp_attributes[i].used = true; + + return ss->temp_attributes + i; + } + } + + BLI_assert_unreachable(); + return nullptr; +} + +SculptAttribute *BKE_sculpt_attribute_get(struct Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name) +{ + SculptSession *ss = ob->sculpt; + + /* See if attribute is cached in ss->temp_attributes. */ + SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name); + + if (attr) { + if (sculpt_attr_update(ob, attr)) { + sculpt_attribute_update_refs(ob); + } + + return attr; + } + + /* Does attribute exist in CustomData layout? */ + CustomData *cdata = sculpt_get_cdata(ob, domain); + if (cdata) { + int index = CustomData_get_named_layer_index(cdata, proptype, name); + + if (index != -1) { + int totelem = 0; + + switch (domain) { + case ATTR_DOMAIN_POINT: + totelem = BKE_sculptsession_vertex_count(ss); + break; + case ATTR_DOMAIN_FACE: + totelem = ss->totfaces; + break; + default: + BLI_assert_unreachable(); + break; + } + + attr = sculpt_alloc_attr(ss); + + attr->used = true; + attr->domain = domain; + attr->proptype = proptype; + attr->data = cdata->layers[index].data; + attr->bmesh_cd_offset = cdata->layers[index].offset; + attr->elem_num = totelem; + attr->layer = cdata->layers + index; + attr->elem_size = CustomData_get_elem_size(attr->layer); + + BLI_strncpy_utf8(attr->name, name, sizeof(attr->name)); + return attr; + } + } + + return nullptr; +} + +static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params, + PBVHType pbvhtype, + bool flat_array_for_bmesh) +{ + SculptSession *ss = ob->sculpt; + SculptAttribute *attr = BKE_sculpt_attribute_get(ob, domain, proptype, name); + + if (attr) { + return attr; + } + + attr = sculpt_alloc_attr(ss); + + /* Create attribute. */ + sculpt_attribute_create( + ss, ob, domain, proptype, name, attr, params, pbvhtype, flat_array_for_bmesh); + sculpt_attribute_update_refs(ob); + + return attr; +} + +SculptAttribute *BKE_sculpt_attribute_ensure(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params) +{ + SculptAttributeParams temp_params = *params; + + return sculpt_attribute_ensure_ex( + ob, domain, proptype, name, &temp_params, BKE_pbvh_type(ob->sculpt->pbvh), true); +} + +static void sculptsession_bmesh_attr_update_internal(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + sculptsession_bmesh_add_layers(ob); + + if (ss->pbvh) { + BKE_pbvh_update_bmesh_offsets(ss->pbvh, + ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset, + ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); + } +} + +void sculptsession_bmesh_add_layers(Object *ob) +{ + SculptSession *ss = ob->sculpt; + SculptAttributeParams params = {0}; + + ss->attrs.dyntopo_node_id_vertex = sculpt_attribute_ensure_ex( + ob, + ATTR_DOMAIN_POINT, + CD_PROP_INT32, + SCULPT_ATTRIBUTE_NAME(dyntopo_node_id_vertex), + ¶ms, + PBVH_BMESH, + false); + + ss->attrs.dyntopo_node_id_face = sculpt_attribute_ensure_ex( + ob, + ATTR_DOMAIN_FACE, + CD_PROP_INT32, + SCULPT_ATTRIBUTE_NAME(dyntopo_node_id_face), + ¶ms, + PBVH_BMESH, + false); +} + +void BKE_sculpt_attributes_destroy_temporary_stroke(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr = ss->temp_attributes + i; + + if (attr->params.stroke_only) { + BKE_sculpt_attribute_destroy(ob, attr); + } + } +} + +static void sculpt_attribute_update_refs(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + /* run twice, in case sculpt_attr_update had to recreate a layer and + messed up the bmesh offsets. */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < SCULPT_MAX_ATTRIBUTES; j++) { + SculptAttribute *attr = ss->temp_attributes + j; + + if (attr->used) { + sculpt_attr_update(ob, attr); + } + } + + if (ss->bm) { + sculptsession_bmesh_attr_update_internal(ob); + } + } + + Mesh *me = BKE_object_get_original_mesh(ob); + + if (ss->pbvh) { + BKE_pbvh_update_active_vcol(ss->pbvh, me); + } +} + +void BKE_sculpt_attribute_destroy_temporary_all(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr = ss->temp_attributes + i; + + if (attr->used && !attr->params.permanent) { + BKE_sculpt_attribute_destroy(ob, attr); + } + } +} + +bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr) +{ + SculptSession *ss = ob->sculpt; + eAttrDomain domain = attr->domain; + + BLI_assert(attr->used); + + /* Remove from convenience pointer struct. */ + SculptAttribute **ptrs = (SculptAttribute **)&ss->attrs; + int ptrs_num = sizeof(ss->attrs) / sizeof(void *); + + for (int i = 0; i < ptrs_num; i++) { + if (ptrs[i] == attr) { + ptrs[i] = nullptr; + } + } + + /* Remove from internal temp_attributes array. */ + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr2 = ss->temp_attributes + i; + + if (STREQ(attr2->name, attr->name) && attr2->domain == attr->domain && + attr2->proptype == attr->proptype) { + + attr2->used = false; + } + } + + Mesh *me = BKE_object_get_original_mesh(ob); + + if (attr->params.simple_array) { + MEM_SAFE_FREE(attr->data); + } + else if (ss->bm) { + CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &ss->bm->vdata : &ss->bm->pdata; + + BM_data_layer_free_named(ss->bm, cdata, attr->name); + } + else { + CustomData *cdata = nullptr; + int totelem = 0; + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = ss->bm ? &ss->bm->vdata : &me->vdata; + totelem = ss->totvert; + break; + case ATTR_DOMAIN_FACE: + cdata = ss->bm ? &ss->bm->pdata : &me->pdata; + totelem = ss->totfaces; + break; + default: + BLI_assert_unreachable(); + return false; + } + + /* We may have been called after destroying ss->bm in which case attr->layer + * might be invalid. + */ + int layer_i = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name); + if (layer_i != 0) { + CustomData_free_layer(cdata, attr->proptype, totelem, layer_i); + } + + sculpt_attribute_update_refs(ob); + } + + attr->data = nullptr; + attr->used = false; + + return true; +} |