diff options
Diffstat (limited to 'source/blender/blenkernel/intern/paint.c')
-rw-r--r-- | source/blender/blenkernel/intern/paint.c | 211 |
1 files changed, 161 insertions, 50 deletions
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 545d1bdee13..d726a4b1e37 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -38,6 +38,7 @@ #include "DNA_workspace_types.h" #include "BLI_bitmap.h" +#include "BLI_hash.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" #include "BLI_utildefines.h" @@ -124,6 +125,16 @@ 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) +{ + /* Whole Palette is preserved accross undo's, and it has no extra pointer, simple. */ + /* Note: We do not care about potential internal references to self here, Palette has none. */ + /* Note: We do not swap IDProperties, as dealing with potential ID pointers in those would be + * fairly delicate. */ + BKE_lib_id_swap(NULL, id_new, id_old); + SWAP(IDProperty *, id_new->properties, id_old->properties); +} + IDTypeInfo IDType_ID_PAL = { .id_code = ID_PAL, .id_filter = FILTER_ID_PAL, @@ -132,7 +143,7 @@ IDTypeInfo IDType_ID_PAL = { .name = "Palette", .name_plural = "palettes", .translation_context = BLT_I18NCONTEXT_ID_PALETTE, - .flags = 0, + .flags = IDTYPE_FLAGS_NO_ANIMDATA, .init_data = palette_init_data, .copy_data = palette_copy_data, @@ -145,6 +156,8 @@ IDTypeInfo IDType_ID_PAL = { .blend_read_data = palette_blend_read_data, .blend_read_lib = NULL, .blend_read_expand = NULL, + + .blend_read_undo_preserve = palette_undo_preserve, }; static void paint_curve_copy_data(Main *UNUSED(bmain), @@ -193,7 +206,7 @@ IDTypeInfo IDType_ID_PC = { .name = "PaintCurve", .name_plural = "paint_curves", .translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE, - .flags = 0, + .flags = IDTYPE_FLAGS_NO_ANIMDATA, .init_data = NULL, .copy_data = paint_curve_copy_data, @@ -206,6 +219,8 @@ IDTypeInfo IDType_ID_PC = { .blend_read_data = paint_curve_blend_read_data, .blend_read_lib = NULL, .blend_read_expand = NULL, + + .blend_read_undo_preserve = NULL, }; const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; @@ -415,10 +430,12 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) return "gpencil_sculpt_tool"; case PAINT_MODE_WEIGHT_GPENCIL: return "gpencil_weight_tool"; - default: - /* invalid paint mode */ - return NULL; + case PAINT_MODE_INVALID: + break; } + + /* Invalid paint mode. */ + return NULL; } Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) @@ -669,18 +686,11 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) { PaintCurve *pc; - pc = BKE_libblock_alloc(bmain, ID_PC, name, 0); + pc = BKE_id_new(bmain, ID_PC, name); return pc; } -PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc) -{ - PaintCurve *pc_copy; - BKE_id_copy(bmain, &pc->id, (ID **)&pc_copy); - return pc_copy; -} - Palette *BKE_paint_palette(Paint *p) { return p ? p->palette : NULL; @@ -738,13 +748,6 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } -Palette *BKE_palette_copy(Main *bmain, const Palette *palette) -{ - Palette *palette_copy; - BKE_id_copy(bmain, &palette->id, (ID **)&palette_copy); - return palette_copy; -} - PaletteColor *BKE_palette_color_add(Palette *palette) { PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color"); @@ -1141,7 +1144,7 @@ void BKE_paint_free(Paint *paint) } /* called when copying scene settings, so even if 'src' and 'tar' are the same - * still do a id_us_plus(), rather then if we were copying between 2 existing + * still do a id_us_plus(), rather than if we were copying between 2 existing * scenes where a matching value should decrease the existing user count as * with paint_brush_set() */ void BKE_paint_copy(Paint *src, Paint *tar, const int flag) @@ -1173,6 +1176,56 @@ void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) } } +void BKE_paint_blend_write(BlendWriter *writer, Paint *p) +{ + if (p->cavity_curve) { + BKE_curvemapping_blend_write(writer, p->cavity_curve); + } + BLO_write_struct_array(writer, PaintToolSlot, p->tool_slots_len, p->tool_slots); +} + +void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Paint *p) +{ + if (p->num_input_samples < 1) { + p->num_input_samples = 1; + } + + BLO_read_data_address(reader, &p->cavity_curve); + if (p->cavity_curve) { + BKE_curvemapping_blend_read(reader, p->cavity_curve); + } + else { + BKE_paint_cavity_curve_preset(p, CURVE_PRESET_LINE); + } + + BLO_read_data_address(reader, &p->tool_slots); + + /* Workaround for invalid data written in older versions. */ + const size_t expected_size = sizeof(PaintToolSlot) * p->tool_slots_len; + if (p->tool_slots && MEM_allocN_len(p->tool_slots) < expected_size) { + MEM_freeN(p->tool_slots); + p->tool_slots = MEM_callocN(expected_size, "PaintToolSlot"); + } + + BKE_paint_runtime_init(scene->toolsettings, p); +} + +void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p) +{ + if (p) { + BLO_read_id_address(reader, sce->id.lib, &p->brush); + for (int i = 0; i < p->tool_slots_len; i++) { + if (p->tool_slots[i].brush != NULL) { + BLO_read_id_address(reader, sce->id.lib, &p->tool_slots[i].brush); + } + } + BLO_read_id_address(reader, sce->id.lib, &p->palette); + p->paint_cursor = NULL; + + BKE_paint_runtime_init(sce->toolsettings, p); + } +} + /* returns non-zero if any of the face's vertices * are hidden, zero otherwise */ bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *mloop) @@ -1309,7 +1362,9 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) MEM_SAFE_FREE(gmap->poly_map_mem); } -/* Write out the sculpt dynamic-topology BMesh to the Mesh */ +/** + * Write out the sculpt dynamic-topology #BMesh to the #Mesh. + */ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) { SculptSession *ss = ob->sculpt; @@ -1606,14 +1661,10 @@ static void sculpt_update_object(Depsgraph *depsgraph, /* Sculpt Face Sets. */ if (use_face_sets) { if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - ss->face_sets = CustomData_add_layer( - &me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly); - for (int i = 0; i < me->totpoly; i++) { - ss->face_sets[i] = 1; - } - - /* Set the default face set color if the datalayer did not exist. */ - me->face_sets_color_default = 1; + /* By checking here if the data-layer already exist this avoids copying the visibility from + * the mesh and looping over all vertices on every sculpt editing operation, using this + * function only the first time the Face Sets data-layer needs to be created. */ + BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(me); } ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); } @@ -1747,17 +1798,16 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object) DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY); } +/** \warning Expects a fully evaluated depsgraph. */ void BKE_sculpt_update_object_for_edit( Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors) { - /* Update from sculpt operators and undo, to update sculpt session - * and PBVH after edits. */ - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig); - Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); - BLI_assert(ob_orig == DEG_get_original_object(ob_orig)); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig); + Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); + BLI_assert(me_eval != NULL); + sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors); } @@ -1878,28 +1928,70 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc return deformed; } -static void sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) { + const int face_sets_default_visible_id = 1; + const int face_sets_default_hidden_id = -(face_sets_default_visible_id + 1); + + bool initialize_new_face_sets = false; + + if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { + /* Make everything visible. */ + int *current_face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + for (int i = 0; i < mesh->totpoly; i++) { + current_face_sets[i] = abs(current_face_sets[i]); + } + } + else { + initialize_new_face_sets = true; + int *new_face_sets = CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly); + + /* Initialize the new Face Set data-layer with a default valid visible ID and set the default + * color to render it white. */ + for (int i = 0; i < mesh->totpoly; i++) { + new_face_sets[i] = face_sets_default_visible_id; + } + mesh->face_sets_color_default = face_sets_default_visible_id; + } + int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); - if (!face_sets) { - return; + + for (int i = 0; i < mesh->totpoly; i++) { + if (!(mesh->mpoly[i].flag & ME_HIDE)) { + continue; + } + + if (initialize_new_face_sets) { + /* When initializing a new Face Set data-layer, assign a new hidden Face Set ID to hidden + * vertices. This way, we get at initial split in two Face Sets between hidden and + * visible vertices based on the previous mesh visibly from other mode that can be + * useful in some cases. */ + face_sets[i] = face_sets_default_hidden_id; + } + else { + /* Otherwise, set the already existing Face Set ID to hidden. */ + face_sets[i] = -abs(face_sets[i]); + } } +} - for (int i = 0; i < mesh->totvert; i++) { - mesh->mvert[i].flag |= ME_HIDE; +void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +{ + int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + if (!face_sets) { + return; } for (int i = 0; i < mesh->totpoly; i++) { - if (face_sets[i] >= 0) { - for (int l = 0; l < mesh->mpoly[i].totloop; l++) { - MLoop *loop = &mesh->mloop[mesh->mpoly[i].loopstart + l]; - mesh->mvert[loop->v].flag &= ~ME_HIDE; - } - } + const bool is_face_set_visible = face_sets[i] >= 0; + SET_FLAG_FROM_TEST(mesh->mpoly[i].flag, !is_face_set_visible, ME_HIDE); } + + BKE_mesh_flush_hidden_from_polys(mesh); } -static void sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) +void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) { int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); if (!face_sets) { @@ -1932,8 +2024,9 @@ static void sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *sub void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg) { - sculpt_sync_face_sets_visibility_to_base_mesh(mesh); - sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg); + BKE_sculpt_face_sets_ensure_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); } static PBVH *build_pbvh_for_dynamic_topology(Object *ob) @@ -2086,3 +2179,21 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d) /* Multires and dyntopo always draw directly from the PBVH. */ return true; } + +/* Returns the Face Set random color for rendering in the overlay given its ID and a color seed. */ +#define GOLDEN_RATIO_CONJUGATE 0.618033988749895f +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)); + 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); + hsv_to_rgb(random_mod_hue, + 0.6f + (random_mod_sat * 0.25f), + 1.0f - (random_mod_val * 0.35f), + &rgba[0], + &rgba[1], + &rgba[2]); + rgba_float_to_uchar(r_color, rgba); +} |