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/blenkernel/intern/paint.c')
-rw-r--r--source/blender/blenkernel/intern/paint.c211
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);
+}