Paint: Store brush and palette colors in scene linear colorspace

For historical reasons these were stored in sRGB space, which caused all
kinds of complexity.

* For image painting, it now properly uses the byte buffer colorspace
  instead of assuming sRGB or display colorspace. This can be more expensive,
  so there is a fast path for sRGB buffers (and for fixed brush colors).
* Lots of code was changed to remove conversion when painting float images
  or vertex colors, and added when painting byte images.
* For non-color data, there is now no colorspace conversion between the brush
  color and image pixels, and #143642 was basically reverted because of that.

Compatibility notes:

* Backwards compatibility is not perfect, as we can not determine if the
  brush has non-color data in isolation. We always convert sRGB to linear,
  and existing brushes configured with non-color data need to be manually
  fixed.
* There is forward compatibility, the old sRGB value is still stored next
  to the scene linear value.

Pull Request: https://projects.blender.org/blender/blender/pulls/144400
This commit is contained in:
Brecht Van Lommel
2025-08-26 17:10:16 +02:00
parent 8adb3e758f
commit 6aa11a304c
47 changed files with 397 additions and 331 deletions

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 64
#define BLENDER_FILE_SUBVERSION 65
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -185,6 +185,9 @@ std::optional<BrushColorJitterSettings> BKE_brush_color_jitter_get_settings(cons
const float *BKE_brush_secondary_color_get(const Paint *paint, const Brush *brush);
void BKE_brush_color_set(Paint *paint, Brush *brush, const float color[3]);
void BKE_brush_color_sync_legacy(Brush *brush);
void BKE_brush_color_sync_legacy(UnifiedPaintSettings *ups);
int BKE_brush_size_get(const Paint *paint, const Brush *brush);
void BKE_brush_size_set(Paint *paint, Brush *brush, int size);

View File

@@ -140,11 +140,14 @@ bool BKE_palette_is_empty(const Palette *palette);
void BKE_palette_color_remove(Palette *palette, PaletteColor *color);
void BKE_palette_clear(Palette *palette);
void BKE_palette_color_set(PaletteColor *color, const float rgb[3]);
void BKE_palette_color_sync_legacy(PaletteColor *color);
void BKE_palette_sort_hsv(tPaletteColorHSV *color_array, int totcol);
void BKE_palette_sort_svh(tPaletteColorHSV *color_array, int totcol);
void BKE_palette_sort_vhs(tPaletteColorHSV *color_array, int totcol);
void BKE_palette_sort_luminance(tPaletteColorHSV *color_array, int totcol);
bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, bool linear);
bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name);
/* Paint curves. */

View File

@@ -21,6 +21,7 @@
#include "BLI_listbase.h"
#include "BLI_math_base.hh"
#include "BLI_math_color.h"
#include "BLI_rand.h"
#include "BLT_translation.hh"
@@ -543,8 +544,8 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(fill_threshold);
FROM_DEFAULT(flag);
FROM_DEFAULT(sampling_flag);
FROM_DEFAULT_PTR(rgb);
FROM_DEFAULT_PTR(secondary_rgb);
FROM_DEFAULT_PTR(color);
FROM_DEFAULT_PTR(secondary_color);
FROM_DEFAULT(spacing);
FROM_DEFAULT(smooth_stroke_radius);
FROM_DEFAULT(smooth_stroke_factor);
@@ -1119,9 +1120,9 @@ float BKE_brush_sample_masktex(
const float *BKE_brush_color_get(const Paint *paint, const Brush *brush)
{
if (BKE_paint_use_unified_color(paint)) {
return paint->unified_paint_settings.rgb;
return paint->unified_paint_settings.color;
}
return brush->rgb;
return brush->color;
}
/** Get color jitter settings if enabled. */
@@ -1133,7 +1134,7 @@ std::optional<BrushColorJitterSettings> BKE_brush_color_jitter_get_settings(cons
return std::nullopt;
}
const UnifiedPaintSettings settings = paint->unified_paint_settings;
const UnifiedPaintSettings &settings = paint->unified_paint_settings;
return BrushColorJitterSettings{
settings.color_jitter_flag,
settings.hsv_jitter[0],
@@ -1163,23 +1164,39 @@ std::optional<BrushColorJitterSettings> BKE_brush_color_jitter_get_settings(cons
const float *BKE_brush_secondary_color_get(const Paint *paint, const Brush *brush)
{
if (BKE_paint_use_unified_color(paint)) {
return paint->unified_paint_settings.secondary_rgb;
return paint->unified_paint_settings.secondary_color;
}
return brush->secondary_rgb;
return brush->secondary_color;
}
void BKE_brush_color_set(Paint *paint, Brush *brush, const float color[3])
{
if (BKE_paint_use_unified_color(paint)) {
UnifiedPaintSettings *ups = &paint->unified_paint_settings;
copy_v3_v3(ups->rgb, color);
copy_v3_v3(ups->color, color);
BKE_brush_color_sync_legacy(ups);
}
else {
copy_v3_v3(brush->rgb, color);
copy_v3_v3(brush->color, color);
BKE_brush_tag_unsaved_changes(brush);
BKE_brush_color_sync_legacy(brush);
}
}
void BKE_brush_color_sync_legacy(Brush *brush)
{
/* For forward compatibility. */
linearrgb_to_srgb_v3_v3(brush->rgb, brush->color);
linearrgb_to_srgb_v3_v3(brush->secondary_rgb, brush->secondary_color);
}
void BKE_brush_color_sync_legacy(UnifiedPaintSettings *ups)
{
/* For forward compatibility. */
linearrgb_to_srgb_v3_v3(ups->rgb, ups->color);
linearrgb_to_srgb_v3_v3(ups->secondary_rgb, ups->secondary_color);
}
void BKE_brush_size_set(Paint *paint, Brush *brush, int size)
{
UnifiedPaintSettings *ups = &paint->unified_paint_settings;

View File

@@ -57,6 +57,8 @@
#include "BLO_read_write.hh"
#include "IMB_colormanagement.hh"
static CLG_LogRef LOG = {"geom.gpencil"};
static void greasepencil_copy_data(Main * /*bmain*/,
@@ -1197,7 +1199,8 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
/* Create Colors. */
for (int i = 0; i < ARRAY_SIZE(hexcol); i++) {
PaletteColor *palcol = BKE_palette_color_add(palette);
hex_to_rgb(hexcol[i], palcol->rgb, palcol->rgb + 1, palcol->rgb + 2);
hex_to_rgb(hexcol[i], palcol->color, palcol->color + 1, palcol->color + 2);
IMB_colormanagement_srgb_to_scene_linear_v3(palcol->color, palcol->color);
}
}

View File

@@ -6,6 +6,9 @@
* \ingroup bke
*/
/* ALlow using deprecated color for sync legacy. */
#define DNA_DEPRECATED_ALLOW
#include <cstdlib>
#include <cstring>
#include <optional>
@@ -73,6 +76,8 @@
#include "BLO_read_write.hh"
#include "IMB_colormanagement.hh"
#include "bmesh.hh"
using blender::float3;
@@ -1401,6 +1406,17 @@ void BKE_palette_clear(Palette *palette)
palette->active_color = 0;
}
void BKE_palette_color_set(PaletteColor *color, const float rgb[3])
{
copy_v3_v3(color->color, rgb);
BKE_palette_color_sync_legacy(color);
}
void BKE_palette_color_sync_legacy(PaletteColor *color)
{
linearrgb_to_srgb_v3_v3(color->rgb, color->color);
}
Palette *BKE_palette_add(Main *bmain, const char *name)
{
Palette *palette = BKE_id_new<Palette>(bmain, name);
@@ -1554,7 +1570,7 @@ void BKE_palette_sort_luminance(tPaletteColorHSV *color_array, const int totcol)
qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_luminance);
}
bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, const bool linear)
bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name)
{
tPaletteColorHSV *color_array = nullptr;
tPaletteColorHSV *col_elm = nullptr;
@@ -1596,10 +1612,8 @@ bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, co
col_elm = &color_array[i];
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
copy_v3_v3(palcol->rgb, col_elm->rgb);
if (linear) {
linearrgb_to_srgb_v3_v3(palcol->rgb, palcol->rgb);
}
/* Hex was stored as sRGB. */
IMB_colormanagement_srgb_to_scene_linear_v3(palcol->color, col_elm->rgb);
}
}
done = true;
@@ -1710,8 +1724,8 @@ static void paint_init_data(Paint &paint)
if (!paint.unified_paint_settings.curve_rand_value) {
paint.unified_paint_settings.curve_rand_value = BKE_paint_default_curve();
}
copy_v3_v3(paint.unified_paint_settings.rgb, default_ups.rgb);
copy_v3_v3(paint.unified_paint_settings.secondary_rgb, default_ups.secondary_rgb);
copy_v3_v3(paint.unified_paint_settings.color, default_ups.color);
copy_v3_v3(paint.unified_paint_settings.secondary_color, default_ups.secondary_color);
}
bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
@@ -1737,10 +1751,10 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
(Paint *)ts->curves_sculpt,
(Paint *)&ts->imapaint));
#ifndef NDEBUG
Paint paint_test = **r_paint;
Paint paint_test = blender::dna::shallow_copy(**r_paint);
paint_runtime_init(ts, *r_paint);
/* Swap so debug doesn't hide errors when release fails. */
std::swap(**r_paint, paint_test);
blender::dna::shallow_swap(**r_paint, paint_test);
BLI_assert(paint_test.runtime->ob_mode == (*r_paint)->runtime->ob_mode);
#endif
}
@@ -1755,7 +1769,7 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
else if ((Sculpt **)r_paint == &ts->sculpt) {
Sculpt *data = MEM_callocN<Sculpt>(__func__);
*data = *DNA_struct_default_get(Sculpt);
*data = blender::dna::shallow_copy(*DNA_struct_default_get(Sculpt));
paint = &data->paint;
paint_init_data(*paint);

View File

@@ -1585,7 +1585,7 @@ static void scene_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old)
* (like object ones). */
scene_foreach_toolsettings(
nullptr, scene_new->toolsettings, true, reader, scene_old->toolsettings);
std::swap(*scene_old->toolsettings, *scene_new->toolsettings);
blender::dna::shallow_swap(*scene_old->toolsettings, *scene_new->toolsettings);
}
}

View File

@@ -1090,7 +1090,7 @@ void blo_do_versions_410(FileData *fd, Library * /*lib*/, Main *bmain)
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
Sculpt *sculpt = scene->toolsettings->sculpt;
if (sculpt != nullptr) {
Sculpt default_sculpt = *DNA_struct_default_get(Sculpt);
Sculpt default_sculpt = blender::dna::shallow_copy(*DNA_struct_default_get(Sculpt));
sculpt->automasking_boundary_edges_propagation_steps =
default_sculpt.automasking_boundary_edges_propagation_steps;
}

View File

@@ -4681,7 +4681,8 @@ void do_versions_after_linking_450(FileData * /*fd*/, Main *bmain)
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 76)) {
ToolSettings toolsettings_default = *DNA_struct_default_get(ToolSettings);
ToolSettings toolsettings_default = blender::dna::shallow_copy(
*DNA_struct_default_get(ToolSettings));
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->toolsettings->snap_playhead_mode = toolsettings_default.snap_playhead_mode;
scene->toolsettings->snap_step_frames = toolsettings_default.snap_step_frames;

View File

@@ -20,13 +20,16 @@
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_function_ref.hh"
#include "BLI_listbase.h"
#include "BLI_math_color.h"
#include "BLI_math_numbers.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
@@ -741,42 +744,47 @@ static void version_seq_text_from_legacy(Main *bmain)
}
}
static void apply_unified_paint_settings_to_all_modes(Scene &scene)
static void for_each_mode_paint_settings(
Scene &scene, blender::FunctionRef<void(Scene &scene, Paint *paint)> func)
{
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->vpaint));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->wpaint));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->sculpt));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->gp_paint));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->gp_vertexpaint));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->gp_sculptpaint));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->gp_weightpaint));
func(scene, reinterpret_cast<Paint *>(scene.toolsettings->curves_sculpt));
func(scene, reinterpret_cast<Paint *>(&scene.toolsettings->imapaint));
}
static void copy_unified_paint_settings(Scene &scene, Paint *paint)
{
if (paint == nullptr) {
return;
}
const UnifiedPaintSettings &scene_ups = scene.toolsettings->unified_paint_settings;
auto apply_to_paint = [&](Paint *paint) {
if (paint == nullptr) {
return;
}
UnifiedPaintSettings &ups = paint->unified_paint_settings;
UnifiedPaintSettings &ups = paint->unified_paint_settings;
ups.size = scene_ups.size;
ups.unprojected_radius = scene_ups.unprojected_radius;
ups.alpha = scene_ups.alpha;
ups.weight = scene_ups.weight;
copy_v3_v3(ups.rgb, scene_ups.rgb);
copy_v3_v3(ups.secondary_rgb, scene_ups.secondary_rgb);
ups.color_jitter_flag = scene_ups.color_jitter_flag;
copy_v3_v3(ups.hsv_jitter, scene_ups.hsv_jitter);
ups.size = scene_ups.size;
ups.unprojected_radius = scene_ups.unprojected_radius;
ups.alpha = scene_ups.alpha;
ups.weight = scene_ups.weight;
copy_v3_v3(ups.color, scene_ups.color);
copy_v3_v3(ups.rgb, scene_ups.rgb);
copy_v3_v3(ups.secondary_color, scene_ups.secondary_color);
copy_v3_v3(ups.secondary_rgb, scene_ups.secondary_rgb);
ups.color_jitter_flag = scene_ups.color_jitter_flag;
copy_v3_v3(ups.hsv_jitter, scene_ups.hsv_jitter);
BLI_assert(ups.curve_rand_hue == nullptr);
BLI_assert(ups.curve_rand_saturation == nullptr);
BLI_assert(ups.curve_rand_value == nullptr);
ups.curve_rand_hue = BKE_curvemapping_copy(scene_ups.curve_rand_hue);
ups.curve_rand_saturation = BKE_curvemapping_copy(scene_ups.curve_rand_saturation);
ups.curve_rand_value = BKE_curvemapping_copy(scene_ups.curve_rand_value);
ups.flag = scene_ups.flag;
};
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->vpaint));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->wpaint));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->sculpt));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->gp_paint));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->gp_vertexpaint));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->gp_sculptpaint));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->gp_weightpaint));
apply_to_paint(reinterpret_cast<Paint *>(scene.toolsettings->curves_sculpt));
apply_to_paint(reinterpret_cast<Paint *>(&scene.toolsettings->imapaint));
BLI_assert(ups.curve_rand_hue == nullptr);
BLI_assert(ups.curve_rand_saturation == nullptr);
BLI_assert(ups.curve_rand_value == nullptr);
ups.curve_rand_hue = BKE_curvemapping_copy(scene_ups.curve_rand_hue);
ups.curve_rand_saturation = BKE_curvemapping_copy(scene_ups.curve_rand_saturation);
ups.curve_rand_value = BKE_curvemapping_copy(scene_ups.curve_rand_value);
ups.flag = scene_ups.flag;
}
/* The Use Alpha option is does not exist in the new generic Mix node, it essentially just
@@ -1905,7 +1913,7 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 26)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
apply_unified_paint_settings_to_all_modes(*scene);
for_each_mode_paint_settings(*scene, copy_unified_paint_settings);
}
}
@@ -2372,7 +2380,7 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 62)) {
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 63)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->r.bake_flag & R_BAKE_MULTIRES) {
scene->r.bake.type = scene->r.bake_mode;
@@ -2399,6 +2407,31 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 65)) {
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
srgb_to_linearrgb_v3_v3(brush->color, brush->rgb);
srgb_to_linearrgb_v3_v3(brush->secondary_color, brush->secondary_rgb);
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
UnifiedPaintSettings &ups = scene->toolsettings->unified_paint_settings;
srgb_to_linearrgb_v3_v3(ups.color, ups.rgb);
srgb_to_linearrgb_v3_v3(ups.secondary_color, ups.secondary_rgb);
for_each_mode_paint_settings(*scene, [](Scene & /*scene*/, Paint *paint) {
if (paint != nullptr) {
UnifiedPaintSettings &ups = paint->unified_paint_settings;
srgb_to_linearrgb_v3_v3(ups.color, ups.rgb);
srgb_to_linearrgb_v3_v3(ups.secondary_color, ups.secondary_rgb);
}
});
}
LISTBASE_FOREACH (Palette *, palette, &bmain->palettes) {
LISTBASE_FOREACH (PaletteColor *, color, &palette->colors) {
srgb_to_linearrgb_v3_v3(color->color, color->rgb);
}
}
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@@ -367,8 +367,8 @@ static void blo_update_defaults_paint(Paint *paint)
paint->unified_paint_settings.alpha = default_ups.alpha;
paint->unified_paint_settings.weight = default_ups.weight;
paint->unified_paint_settings.flag = default_ups.flag;
copy_v3_v3(paint->unified_paint_settings.rgb, default_ups.rgb);
copy_v3_v3(paint->unified_paint_settings.secondary_rgb, default_ups.secondary_rgb);
copy_v3_v3(paint->unified_paint_settings.color, default_ups.color);
copy_v3_v3(paint->unified_paint_settings.secondary_color, default_ups.secondary_color);
if (paint->unified_paint_settings.curve_rand_hue == nullptr) {
paint->unified_paint_settings.curve_rand_hue = BKE_paint_default_curve();
@@ -492,8 +492,8 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
const UnifiedPaintSettings &default_ups = *DNA_struct_default_get(UnifiedPaintSettings);
ts->unified_paint_settings.flag = default_ups.flag;
copy_v3_v3(ts->unified_paint_settings.rgb, default_ups.rgb);
copy_v3_v3(ts->unified_paint_settings.secondary_rgb, default_ups.secondary_rgb);
copy_v3_v3(ts->unified_paint_settings.color, default_ups.color);
copy_v3_v3(ts->unified_paint_settings.secondary_color, default_ups.secondary_color);
if (ts->unified_paint_settings.curve_rand_hue == nullptr) {
ts->unified_paint_settings.curve_rand_hue = BKE_paint_default_curve();

View File

@@ -809,7 +809,7 @@ static wmOperatorStatus grease_pencil_primitive_invoke(bContext *C,
GPPAINT_FLAG_USE_VERTEXCOLOR);
if (use_vertex_color) {
ColorGeometry4f color_base;
srgb_to_linearrgb_v3_v3(color_base, ptd.brush->rgb);
copy_v3_v3(color_base, ptd.brush->color);
color_base.a = ptd.settings->vertex_factor;
ptd.vertex_color = ELEM(ptd.settings->vertex_mode, GPPAINT_MODE_STROKE, GPPAINT_MODE_BOTH) ?
std::make_optional(color_base) :

View File

@@ -360,8 +360,7 @@ static wmOperatorStatus grease_pencil_vertex_paint_set_exec(bContext *C, wmOpera
const float factor = RNA_float_get(op->ptr, "factor");
const bool use_selection_mask = ED_grease_pencil_any_vertex_mask_selection(scene.toolsettings);
float3 color_linear;
srgb_to_linearrgb_v3_v3(color_linear, BKE_brush_color_get(&paint, &brush));
float3 color_linear = BKE_brush_color_get(&paint, &brush);
const ColorGeometry4f target_color(color_linear[0], color_linear[1], color_linear[2], 1.0f);
std::atomic<bool> any_changed;

View File

@@ -88,63 +88,6 @@ static void eyedropper_draw_cb(const wmWindow * /*window*/, void *arg)
eyedropper_draw_cursor_text_region(eye->cb_win_event_xy, eye->sample_text);
}
/* A heuristic to check whether the current eyedropper destination property is used for non-color
* painting. If so, the eyedropper will ignore the PROP_COLOR_GAMMA nature of the property and
* not convert linear colors to display space.
*
* The current logic is targeting texture painting, both 2D and 3D. It assumes that invoking the
* operator from 3D viewport means 3D painting, and invoking from image editor means 2D painting.
*
* For the 3D painting the function checks whether active object is in texture paint mode, and if
* so checks the active image (via material slot, or the explicitly specified image) to have
* non-color (data) colorspace.
*
* For the 2D painting it checks the active image editor's image colorspace.
*
* Since brush color could be re-used from multiple spaces the check is not fully reliable: it is
* possible to invoke sampling from one editor and do stroke in other editor. There is no easy way
* of dealing with this, and it is unlikely to be a common configuration. */
static bool is_data_destination(const bContext *C, const Eyedropper *eye)
{
if (eye->ptr.type != &RNA_Brush) {
return false;
}
const View3D *v3d = CTX_wm_view3d(C);
if (v3d) {
/*const*/ Object *object = CTX_data_active_object(C);
if (!object) {
return false;
}
if ((object->mode & OB_MODE_TEXTURE_PAINT) == 0) {
return false;
}
const Scene *scene = CTX_data_scene(C);
const ImagePaintSettings &settings = scene->toolsettings->imapaint;
Image *image = nullptr;
if (settings.mode == IMAGEPAINT_MODE_MATERIAL) {
Material *material = BKE_object_material_get(object, object->actcol);
if (material && material->texpaintslot) {
image = material->texpaintslot[material->paint_active_slot].ima;
}
}
else if (settings.mode == IMAGEPAINT_MODE_IMAGE) {
image = settings.canvas;
}
return image && IMB_colormanagement_space_name_is_data(image->colorspace_settings.name);
}
const SpaceImage *space_image = CTX_wm_space_image(C);
if (space_image) {
return space_image->image &&
IMB_colormanagement_space_name_is_data(space_image->image->colorspace_settings.name);
}
return false;
}
static bool eyedropper_init(bContext *C, wmOperator *op)
{
Eyedropper *eye = MEM_new<Eyedropper>(__func__);
@@ -194,7 +137,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
eye->draw_handle_sample_text = WM_draw_cb_activate(eye->cb_win, eyedropper_draw_cb, eye);
}
if (prop_subtype != PROP_COLOR && !is_data_destination(C, eye)) {
if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;

View File

@@ -145,9 +145,7 @@ static void eyedropper_grease_pencil_exit(bContext *C, wmOperator *op)
op->customdata = nullptr;
}
static void eyedropper_add_material(bContext *C,
const float3 col_conv,
const MaterialMode mat_mode)
static void eyedropper_add_material(bContext *C, const float3 color, const MaterialMode mat_mode)
{
Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
@@ -166,10 +164,10 @@ static void eyedropper_add_material(bContext *C,
MaterialGPencilStyle *gp_style = ma->gp_style;
if (gp_style != nullptr) {
/* Check stroke color. */
bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) &&
bool found_stroke = compare_v3v3(gp_style->stroke_rgba, color, 0.01f) &&
(gp_style->flag & GP_MATERIAL_STROKE_SHOW);
/* Check fill color. */
bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) &&
bool found_fill = compare_v3v3(gp_style->fill_rgba, color, 0.01f) &&
(gp_style->flag & GP_MATERIAL_FILL_SHOW);
if ((mat_mode == MaterialMode::Stroke) && (found_stroke) &&
@@ -215,7 +213,7 @@ static void eyedropper_add_material(bContext *C,
/* Stroke color. */
gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW;
gp_style_new->flag &= ~GP_MATERIAL_FILL_SHOW;
copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
copy_v3_v3(gp_style_new->stroke_rgba, color);
zero_v4(gp_style_new->fill_rgba);
}
/* Fill Only. */
@@ -224,20 +222,20 @@ static void eyedropper_add_material(bContext *C,
gp_style_new->flag &= ~GP_MATERIAL_STROKE_SHOW;
gp_style_new->flag |= GP_MATERIAL_FILL_SHOW;
zero_v4(gp_style_new->stroke_rgba);
copy_v3_v3(gp_style_new->fill_rgba, col_conv);
copy_v3_v3(gp_style_new->fill_rgba, color);
}
/* Stroke and Fill. */
else if (mat_mode == MaterialMode::Both) {
gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW | GP_MATERIAL_FILL_SHOW;
copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
copy_v3_v3(gp_style_new->fill_rgba, col_conv);
copy_v3_v3(gp_style_new->stroke_rgba, color);
copy_v3_v3(gp_style_new->fill_rgba, color);
}
/* Push undo for new created material. */
ED_undo_push(C, "Add Grease Pencil Material");
}
/* Create a new palette color and palette if needed. */
static void eyedropper_add_palette_color(bContext *C, const float3 col_conv)
static void eyedropper_add_palette_color(bContext *C, const float3 color)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -263,7 +261,7 @@ static void eyedropper_add_palette_color(bContext *C, const float3 col_conv)
Palette *palette = paint->palette;
int i;
LISTBASE_FOREACH_INDEX (PaletteColor *, palcolor, &palette->colors, i) {
if (compare_v3v3(palcolor->rgb, col_conv, 0.01f)) {
if (compare_v3v3(palcolor->color, color, 0.01f)) {
palette->active_color = i;
return;
}
@@ -273,12 +271,12 @@ static void eyedropper_add_palette_color(bContext *C, const float3 col_conv)
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
palette->active_color = BLI_listbase_count(&palette->colors) - 1;
copy_v3_v3(palcol->rgb, col_conv);
BKE_palette_color_set(palcol, color);
}
}
/* Set the active brush's color. */
static void eyedropper_set_brush_color(bContext *C, const float3 &col_conv)
static void eyedropper_set_brush_color(bContext *C, const float3 &color)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -288,7 +286,8 @@ static void eyedropper_set_brush_color(bContext *C, const float3 &col_conv)
return;
}
copy_v3_v3(brush->rgb, col_conv);
copy_v3_v3(brush->color, color);
BKE_brush_color_sync_legacy(brush);
BKE_brush_tag_unsaved_changes(brush);
}
@@ -311,24 +310,15 @@ static void eyedropper_grease_pencil_color_set(bContext *C,
mat_mode = MaterialMode::Both;
}
float3 col_conv = eye->color;
/* Convert from linear rgb space to sRGB space because palette and brush colors are in
* sRGB space, and this conversion is needed to undo the conversion to linear performed by
* eyedropper_color_sample_fl. */
if (eye->display && ELEM(eye->mode, EyeMode::Palette, EyeMode::Brush)) {
IMB_colormanagement_scene_linear_to_srgb_v3(col_conv, col_conv);
}
switch (eye->mode) {
case EyeMode::Material:
eyedropper_add_material(C, col_conv, mat_mode);
eyedropper_add_material(C, eye->color, mat_mode);
break;
case EyeMode::Palette:
eyedropper_add_palette_color(C, col_conv);
eyedropper_add_palette_color(C, eye->color);
break;
case EyeMode::Brush:
eyedropper_set_brush_color(C, col_conv);
eyedropper_set_brush_color(C, eye->color);
break;
}
}

View File

@@ -6660,13 +6660,13 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
RNA_property_float_get_array_at_most(
&but->rnapoin, but->rnaprop, color, ARRAY_SIZE(color));
IMB_colormanagement_srgb_to_scene_linear_v3(color, color);
BKE_brush_color_set(paint, brush, color);
updated = true;
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array_at_most(
&but->rnapoin, but->rnaprop, color, ARRAY_SIZE(color));
IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
BKE_brush_color_set(paint, brush, color);
updated = true;
}

View File

@@ -2403,8 +2403,8 @@ static wmOperatorStatus drop_color_invoke(bContext *C, wmOperator *op, const wmE
}
}
else {
if (!gamma) {
linearrgb_to_srgb_v3_v3(color, color);
if (gamma) {
srgb_to_linearrgb_v3_v3(color, color);
}
ED_imapaint_bucket_fill(C, color, op, event->mval);

View File

@@ -660,7 +660,7 @@ static bke::CurvesGeometry boundary_to_curves(const Scene &scene,
scene.toolsettings->gp_paint, &brush);
if (use_vertex_color) {
ColorGeometry4f vertex_color;
srgb_to_linearrgb_v3_v3(vertex_color, brush.rgb);
copy_v3_v3(vertex_color, brush.color);
vertex_color.a = brush.gpencil_settings->vertex_factor;
if (ELEM(brush.gpencil_settings->vertex_mode, GPPAINT_MODE_FILL, GPPAINT_MODE_BOTH)) {

View File

@@ -166,7 +166,7 @@ static Brush *create_fill_guide_brush()
settings->brush_draw_mode = GP_BRUSH_MODE_VERTEXCOLOR;
/* TODO: Use theme setting. */
copy_v3_fl3(fill_guides_brush->rgb, 0.0f, 1.0f, 1.0f);
copy_v3_fl3(fill_guides_brush->color, 0.0f, 1.0f, 1.0f);
settings->vertex_factor = 1.0f;
settings->active_smooth = 0.35f;
@@ -292,7 +292,7 @@ struct PaintOperationExecutor {
use_vertex_color_ = brush_using_vertex_color(scene_->toolsettings->gp_paint, brush_);
if (use_vertex_color_) {
ColorGeometry4f color_base;
srgb_to_linearrgb_v3_v3(color_base, brush_->rgb);
copy_v3_v3(color_base, brush_->color);
color_base.a = settings_->vertex_factor;
if (ELEM(settings_->vertex_mode, GPPAINT_MODE_STROKE, GPPAINT_MODE_BOTH)) {
vertex_color_ = color_base;

View File

@@ -90,7 +90,7 @@ void TintOperation::on_stroke_begin(const bContext &C, const InputSample & /*sta
float4 color_linear;
color_linear[3] = 1.0f;
srgb_to_linearrgb_v3_v3(color_linear, BKE_brush_color_get(paint, brush));
copy_v3_v3(color_linear, BKE_brush_color_get(paint, brush));
color_ = ColorGeometry4f(color_linear);

View File

@@ -44,7 +44,7 @@ void VertexPaintOperation::on_stroke_extended(const bContext &C,
const bool do_fill = do_vertex_color_fill(brush);
float color_linear[3];
srgb_to_linearrgb_v3_v3(color_linear, BKE_brush_color_get(&paint, &brush));
copy_v3_v3(color_linear, BKE_brush_color_get(&paint, &brush));
const ColorGeometry4f mix_color(color_linear[0], color_linear[1], color_linear[2], 1.0f);
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {

View File

@@ -41,7 +41,7 @@ void VertexReplaceOperation::on_stroke_extended(const bContext &C,
const bool do_fill = do_vertex_color_fill(brush);
float3 color_linear;
srgb_to_linearrgb_v3_v3(color_linear, BKE_brush_color_get(&paint, &brush));
copy_v3_v3(color_linear, BKE_brush_color_get(&paint, &brush));
const ColorGeometry4f replace_color(color_linear.x, color_linear.y, color_linear.z, 1.0f);
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {

View File

@@ -12,6 +12,7 @@
#include "BLI_listbase.h"
#include "BLI_math_axis_angle.hh"
#include "BLI_math_color.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_rotation.h"
#include "BLI_rect.h"
@@ -1657,7 +1658,12 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext &pcontext)
ELEM(brush->gpencil_settings->vertex_mode,
GPPAINT_MODE_STROKE,
GPPAINT_MODE_BOTH);
color = use_vertex_color_stroke ? float3(brush->rgb) : float4(gp_style->stroke_rgba).xyz();
if (use_vertex_color_stroke) {
IMB_colormanagement_scene_linear_to_srgb_v3(color, brush->color);
}
else {
color = float4(gp_style->stroke_rgba).xyz();
}
}
}
@@ -1669,6 +1675,7 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext &pcontext)
else if (pcontext.mode == PaintMode::VertexGPencil) {
pcontext.pixel_radius = BKE_brush_size_get(pcontext.paint, brush);
color = BKE_brush_color_get(paint, brush);
IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
}
GPU_line_width(1.0f);

View File

@@ -15,8 +15,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.hh"
#include "BLI_noise.hh"
#include "BLI_rand.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -45,7 +45,6 @@
#include "BKE_object.hh"
#include "BKE_paint.hh"
#include "BKE_paint_types.hh"
#include "BKE_report.hh"
#include "BKE_scene.hh"
#include "NOD_texture.h"
@@ -369,7 +368,6 @@ void paint_brush_color_get(const Paint *paint,
bool invert,
float distance,
float pressure,
bool is_data,
float r_color[3])
{
if (invert) {
@@ -394,25 +392,22 @@ void paint_brush_color_get(const Paint *paint,
break;
}
}
/* Gradient / Color-band colors are not considered #PROP_COLOR_GAMMA.
* Brush colors are currently in sRGB though. */
IMB_colormanagement_scene_linear_to_srgb_v3(r_color, color_gr);
copy_v3_v3(r_color, color_gr);
}
else if (color_jitter_settings) {
copy_v3_v3(r_color,
BKE_paint_randomize_color(*color_jitter_settings,
*initial_hsv_jitter,
distance,
pressure,
BKE_brush_color_get(paint, br)));
/* Perform color jitter with sRGB transfer function. This is inconsistent with other
* paint modes which do it in linear space. But arguably it's better to do it in the
* more perceptually uniform color space. */
blender::float3 color = BKE_brush_color_get(paint, br);
linearrgb_to_srgb_v3_v3(color, color);
color = BKE_paint_randomize_color(
*color_jitter_settings, *initial_hsv_jitter, distance, pressure, color);
srgb_to_linearrgb_v3_v3(r_color, color);
}
else {
copy_v3_v3(r_color, BKE_brush_color_get(paint, br));
}
}
if (!is_data) {
IMB_colormanagement_srgb_to_scene_linear_v3(r_color, r_color);
}
}
void paint_brush_init_tex(Brush *brush)
@@ -870,10 +865,12 @@ static wmOperatorStatus brush_colors_flip_exec(bContext *C, wmOperator * /*op*/)
if (BKE_paint_use_unified_color(paint)) {
UnifiedPaintSettings &ups = paint->unified_paint_settings;
swap_v3_v3(ups.rgb, ups.secondary_rgb);
swap_v3_v3(ups.color, ups.secondary_color);
BKE_brush_color_sync_legacy(&ups);
}
else if (br) {
swap_v3_v3(br->rgb, br->secondary_rgb);
swap_v3_v3(br->color, br->secondary_color);
BKE_brush_color_sync_legacy(br);
BKE_brush_tag_unsaved_changes(br);
}
else {

View File

@@ -407,14 +407,8 @@ static ImBuf *brush_painter_imbuf_new(
/* get brush color */
if (brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_DRAW) {
paint_brush_color_get(paint,
brush,
painter->initial_hsv_jitter,
cache->invert,
distance,
pressure,
cache->is_data,
brush_rgb);
paint_brush_color_get(
paint, brush, painter->initial_hsv_jitter, cache->invert, distance, pressure, brush_rgb);
if (cache->is_srgb) {
IMB_colormanagement_scene_linear_to_srgb_v3(brush_rgb, brush_rgb);
@@ -503,14 +497,8 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
/* get brush color */
if (brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_DRAW) {
paint_brush_color_get(paint,
brush,
painter->initial_hsv_jitter,
cache->invert,
0.0f,
1.0f,
cache->is_data,
brush_rgb);
paint_brush_color_get(
paint, brush, painter->initial_hsv_jitter, cache->invert, 0.0f, 1.0f, brush_rgb);
if (cache->is_srgb) {
IMB_colormanagement_scene_linear_to_srgb_v3(brush_rgb, brush_rgb);

View File

@@ -23,6 +23,7 @@
#include "BLI_listbase.h"
#include "BLI_math_base_safe.h"
#include "BLI_math_bits.h"
#include "BLI_math_color.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_geom.h"
#include "BLI_math_vector.hh"
@@ -221,6 +222,11 @@ struct ProjPaintImage {
/** Store flag to enforce validation of undo rectangle. */
bool **valid;
bool touch;
/** Paint color in the colorspace of this image, cached for performance. */
float paint_color_byte[3];
bool is_data;
bool is_srgb;
const ColorSpace *byte_colorspace;
};
/**
@@ -268,8 +274,7 @@ struct ProjPaintState {
/* PROJ_SRC_**** */
int source;
/* the paint color. It can change depending of inverted mode or not */
float paint_color[3];
/* Scene linear paint color. It can change depending on inverted mode or not. */
float paint_color_linear[3];
float dither;
@@ -1974,7 +1979,9 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
uchar rgba_ub[4];
float rgba[4];
project_face_pixel(other_tri_uv, ibuf_other, w, rgba_ub, nullptr);
srgb_to_linearrgb_uchar4(rgba, rgba_ub);
rgba_uchar_to_float(rgba, rgba_ub);
IMB_colormanagement_colorspace_to_scene_linear_v3(rgba,
ibuf_other->byte_buffer.colorspace);
straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
}
}
@@ -1983,8 +1990,8 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
float rgba[4];
project_face_pixel(other_tri_uv, ibuf_other, w, nullptr, rgba);
premul_to_straight_v4(rgba);
linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
IMB_colormanagement_scene_linear_to_colorspace_v3(rgba, ibuf->byte_buffer.colorspace);
rgba_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
}
else { /* char to char */
project_face_pixel(
@@ -5074,16 +5081,23 @@ static void do_projectpaint_draw(ProjPaintState *ps,
int u,
int v)
{
const ProjPaintImage *img = &ps->projImages[projPixel->image_index];
float rgb[3];
uchar rgba_ub[4];
if (ps->is_texbrush) {
mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
/* TODO(sergey): Support texture paint color space. */
linearrgb_to_srgb_v3_v3(rgb, rgb);
if (img->is_srgb) {
/* Fast-ish path for sRGB. */
IMB_colormanagement_scene_linear_to_srgb_v3(rgb, rgb);
}
else if (img->byte_colorspace) {
/* Slow path with arbitrary colorspace. */
IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, img->byte_colorspace);
}
}
else {
copy_v3_v3(rgb, ps->paint_color);
copy_v3_v3(rgb, img->paint_color_byte);
}
if (dither > 0.0f) {
@@ -5322,7 +5336,13 @@ static void do_projectpaint_thread(TaskPool *__restrict /*pool*/, void *ph_v)
IMB_BlendMode(ps->blend));
}
else {
linearrgb_to_srgb_v3_v3(color_f, color_f);
const ProjPaintImage *img = &ps->projImages[projPixel->image_index];
if (img->is_srgb) {
IMB_colormanagement_scene_linear_to_srgb_v3(color_f, color_f);
}
else if (img->byte_colorspace) {
IMB_colormanagement_scene_linear_to_colorspace_v3(color_f, img->byte_colorspace);
}
if (ps->dither > 0.0f) {
float_to_byte_dither_v3(
@@ -5350,10 +5370,11 @@ static void do_projectpaint_thread(TaskPool *__restrict /*pool*/, void *ph_v)
IMB_BlendMode(ps->blend));
}
else {
const ProjPaintImage *img = &ps->projImages[projPixel->image_index];
float mask = float(projPixel->mask) * (1.0f / 65535.0f);
projPixel->newColor.ch[3] = mask * 255 * brush_alpha;
rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
rgb_float_to_uchar(projPixel->newColor.ch, img->paint_color_byte);
IMB_blend_color_byte(projPixel->pixel.ch_pt,
projPixel->origColor.ch_pt,
projPixel->newColor.ch,
@@ -5749,17 +5770,6 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
return touch_any;
}
static bool has_data_projection_paint_image(const ProjPaintState &ps)
{
for (int i = 0; i < ps.image_tot; i++) {
const ImBuf *ibuf = ps.projImages[i].ibuf;
if (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) {
return true;
}
}
return false;
}
static void paint_proj_stroke_ps(const bContext * /*C*/,
void *ps_handle_p,
const float prev_pos[2],
@@ -5790,8 +5800,34 @@ static void paint_proj_stroke_ps(const bContext * /*C*/,
ps->mode == BRUSH_STROKE_INVERT,
distance,
pressure,
has_data_projection_paint_image(*ps),
ps->paint_color);
ps->paint_color_linear);
/* Cache colorspace info per image for performance. */
for (int i = 0; i < ps->image_tot; i++) {
ProjPaintImage *img = &ps->projImages[i];
const ImBuf *ibuf = img->ibuf;
copy_v3_v3(img->paint_color_byte, ps->paint_color_linear);
img->byte_colorspace = nullptr;
img->is_data = false;
img->is_srgb = false;
if (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) {
img->is_data = true;
}
else if (ibuf->byte_buffer.data && ibuf->byte_buffer.colorspace) {
img->byte_colorspace = ibuf->byte_buffer.colorspace;
img->is_srgb = IMB_colormanagement_space_is_srgb(img->byte_colorspace);
if (img->is_srgb) {
IMB_colormanagement_scene_linear_to_srgb_v3(img->paint_color_byte,
img->paint_color_byte);
}
else {
IMB_colormanagement_scene_linear_to_colorspace_v3(img->paint_color_byte,
img->byte_colorspace);
}
}
}
}
else if (ps->brush_type == IMAGE_PAINT_BRUSH_TYPE_MASK) {
ps->stencil_value = brush->weight;

View File

@@ -350,8 +350,7 @@ void paint_brush_color_get(const Paint *paint,
bool invert,
float distance,
float pressure,
bool is_data,
float r_color[3] /* In scene linear colorspace. */);
float r_color[3]);
bool paint_use_opacity_masking(const Paint *paint, const Brush *brush);
void paint_brush_init_tex(Brush *brush);
void paint_brush_exit_tex(Brush *brush);

View File

@@ -14,6 +14,7 @@
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
@@ -42,6 +43,8 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "IMB_colormanagement.hh"
#include "curves_sculpt_intern.hh"
#include "paint_hide.hh"
#include "paint_intern.hh"
@@ -183,11 +186,11 @@ static wmOperatorStatus palette_color_add_exec(bContext *C, wmOperator * /*op*/)
PaintMode::GPencil,
PaintMode::VertexGPencil))
{
copy_v3_v3(color->rgb, BKE_brush_color_get(paint, brush));
copy_v3_v3(color->color, BKE_brush_color_get(paint, brush));
color->value = 0.0;
}
else if (mode == PaintMode::Weight) {
zero_v3(color->rgb);
zero_v3(color->color);
color->value = brush->weight;
}
}
@@ -272,8 +275,10 @@ static wmOperatorStatus palette_extract_img_exec(bContext *C, wmOperator *op)
const int range = int(pow(10.0f, threshold));
for (int row = 0; row < ibuf->y; row++) {
for (int col = 0; col < ibuf->x; col++) {
float color[4];
IMB_sampleImageAtLocation(ibuf, float(col), float(row), false, color);
float color[3];
IMB_sampleImageAtLocation(ibuf, float(col), float(row), color);
/* Convert to sRGB for hex. */
IMB_colormanagement_scene_linear_to_srgb_v3(color, color);
for (int i = 0; i < 3; i++) {
color[i] = truncf(color[i] * range) / range;
}
@@ -285,7 +290,7 @@ static wmOperatorStatus palette_extract_img_exec(bContext *C, wmOperator *op)
}
}
done = BKE_palette_from_hash(bmain, color_table, image->id.name + 2, false);
done = BKE_palette_from_hash(bmain, color_table, image->id.name + 2);
}
/* Free memory. */
@@ -343,9 +348,9 @@ static wmOperatorStatus palette_sort_exec(bContext *C, wmOperator *op)
int t = 0;
LISTBASE_FOREACH (PaletteColor *, color, &palette->colors) {
float h, s, v;
rgb_to_hsv(color->rgb[0], color->rgb[1], color->rgb[2], &h, &s, &v);
rgb_to_hsv(color->color[0], color->color[1], color->color[2], &h, &s, &v);
col_elm = &color_array[t];
copy_v3_v3(col_elm->rgb, color->rgb);
copy_v3_v3(col_elm->rgb, color->color);
col_elm->value = color->value;
col_elm->h = h;
col_elm->s = s;
@@ -376,7 +381,7 @@ static wmOperatorStatus palette_sort_exec(bContext *C, wmOperator *op)
col_elm = &color_array[i];
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
copy_v3_v3(palcol->rgb, col_elm->rgb);
copy_v3_v3(palcol->color, col_elm->rgb);
}
}
}
@@ -489,7 +494,7 @@ static wmOperatorStatus palette_join_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (PaletteColor *, color, &palette_join->colors) {
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
copy_v3_v3(palcol->rgb, color->rgb);
copy_v3_v3(palcol->color, color->color);
palcol->value = color->value;
done = true;
}

View File

@@ -183,25 +183,6 @@ static void paint_sample_color(
SpaceImage *sima = CTX_wm_space_image(C);
const View3D *v3d = CTX_wm_view3d(C);
bool is_data = false;
if (v3d) {
const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *object = BKE_view_layer_active_object_get(view_layer);
const Material *material = BKE_object_material_get(object, object->actcol);
if (material && material->texpaintslot) {
const Image *image = material->texpaintslot[material->paint_active_slot].ima;
is_data = image && IMB_colormanagement_space_name_is_data(image->colorspace_settings.name);
}
}
else {
const Image *image = imapaint->canvas;
is_data = image && IMB_colormanagement_space_name_is_data(image->colorspace_settings.name);
}
}
if (v3d && texpaint_proj) {
/* first try getting a color directly from the mesh faces if possible */
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -279,17 +260,9 @@ static void paint_sample_color(
rgba_f = math::clamp(rgba_f, 0.0f, 1.0f);
straight_to_premul_v4(rgba_f);
if (use_palette) {
if (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) {
copy_v3_v3(color->rgb, rgba_f);
}
else {
linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
}
BKE_palette_color_set(color, rgba_f);
}
else {
if ((ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0) {
linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
}
BKE_brush_color_set(paint, br, rgba_f);
}
}
@@ -297,12 +270,18 @@ static void paint_sample_color(
uchar4 rgba = interp == SHD_INTERP_CLOSEST ?
imbuf::interpolate_nearest_wrap_byte(ibuf, u, v) :
imbuf::interpolate_bilinear_wrap_byte(ibuf, u, v);
float rgba_f[4];
rgba_uchar_to_float(rgba_f, rgba);
if ((ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0) {
IMB_colormanagement_colorspace_to_scene_linear_v3(rgba_f,
ibuf->byte_buffer.colorspace);
}
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
BKE_palette_color_set(color, rgba_f);
}
else {
float rgba_f[3];
rgb_uchar_to_float(rgba_f, rgba);
BKE_brush_color_set(paint, br, rgba_f);
}
}
@@ -320,13 +299,10 @@ static void paint_sample_color(
/* Sample from the active image buffer. The sampled color is in
* Linear Scene Reference Space. */
float rgba_f[3];
bool is_data;
if (ED_space_image_color_sample(sima, region, blender::int2(x, y), rgba_f, &is_data)) {
if (!is_data) {
linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
}
if (use_palette) {
copy_v3_v3(color->rgb, rgba_f);
BKE_palette_color_set(color, rgba_f);
}
else {
BKE_brush_color_set(paint, br, rgba_f);
@@ -343,25 +319,13 @@ static void paint_sample_color(
blender::int2(x + region->winrct.xmin, y + region->winrct.ymin),
rgb_fl);
/* The sampled color is in display space, which is what it is supposed to be when painting on
* an image with known colorspace. When painting on non-color/data textures convert display to
* scene linear so that painting with the new color will produce the same color after the
* texture comes via rendering/color management. */
if (is_data) {
/* Note that the logic for the image sampling above uses hardcoded linear<->srgb conversion,
* as well does the do_projectpaint_draw(). For the consistency use hardcoded conversion here
* as well.
*
* Ideally it should become something like:
* const ColorManagedDisplay *display = IMB_colormanagement_display_get_named(
* scene->display_settings.display_device);
* IMB_colormanagement_display_to_scene_linear_v3(rgb_fl, display);
*/
srgb_to_linearrgb_v3_v3(rgb_fl, rgb_fl);
}
/* The sampled color is in display colorspace, convert to scene linear. */
const ColorManagedDisplay *display = IMB_colormanagement_display_get_named(
scene->display_settings.display_device);
IMB_colormanagement_display_to_scene_linear_v3(rgb_fl, display);
if (use_palette) {
copy_v3_v3(color->rgb, rgb_fl);
BKE_palette_color_set(color, rgb_fl);
}
else {
BKE_brush_color_set(paint, br, rgb_fl);

View File

@@ -650,7 +650,7 @@ static ColorPaint4f vpaint_get_current_col(VPaint &vp, bool secondary)
float color[4];
const float *brush_color = secondary ? BKE_brush_secondary_color_get(&vp.paint, brush) :
BKE_brush_color_get(&vp.paint, brush);
IMB_colormanagement_srgb_to_scene_linear_v3(color, brush_color);
copy_v3_v3(color, brush_color);
color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */

View File

@@ -2579,7 +2579,6 @@ static void cache_initial_config_set(bContext *C, wmOperator *op, Cache &expand_
BKE_curvemapping_init(expand_cache.brush->curve);
copy_v4_fl(expand_cache.fill_color, 1.0f);
copy_v3_v3(expand_cache.fill_color, BKE_brush_color_get(paint, expand_cache.brush));
IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache.fill_color, expand_cache.fill_color);
expand_cache.scene = CTX_data_scene(C);
expand_cache.texture_distortion_strength = 0.0f;

View File

@@ -380,7 +380,6 @@ static void sculpt_color_filter_apply(bContext *C, wmOperator *op, Object &ob)
float fill_color[3];
RNA_float_get_array(op->ptr, "fill_color", fill_color);
IMB_colormanagement_srgb_to_scene_linear_v3(fill_color, fill_color);
Mesh &mesh = *static_cast<Mesh *>(ob.data);
if (filter_strength < 0.0 && ss.filter_cache->pre_smoothed_color.is_empty()) {
@@ -606,7 +605,7 @@ void SCULPT_OT_color_filter(wmOperatorType *ot)
0.0f,
1.0f);
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MESH);
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_subtype(prop, PROP_COLOR);
}
} // namespace blender::ed::sculpt_paint::color

View File

@@ -650,9 +650,7 @@ static wmOperatorStatus sample_color_invoke(bContext *C, wmOperator *op, const w
std::get<int>(ss.active_vert()));
}
float color_srgb[3];
IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb, active_vertex_color);
BKE_brush_color_set(&sd.paint, &brush, color_srgb);
BKE_brush_color_set(&sd.paint, &brush, active_vertex_color);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, &brush);
@@ -1195,7 +1193,7 @@ static wmOperatorStatus mask_from_cavity_exec(bContext *C, wmOperator *op)
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
/* Set up automasking settings. */
Sculpt scene_copy = sd;
Sculpt scene_copy = dna::shallow_copy(sd);
MaskSettingsSource src = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
switch (src) {
@@ -1389,7 +1387,7 @@ static wmOperatorStatus mask_from_boundary_exec(bContext *C, wmOperator *op)
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
/* Set up automasking settings. */
Sculpt scene_copy = sd;
Sculpt scene_copy = dna::shallow_copy(sd);
MaskSettingsSource src = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
switch (src) {

View File

@@ -430,8 +430,6 @@ static void do_paint_brush_task(const Depsgraph &depsgraph,
float3 brush_color_rgb = ss.cache->invert ? BKE_brush_secondary_color_get(&paint, &brush) :
BKE_brush_color_get(&paint, &brush);
IMB_colormanagement_srgb_to_scene_linear_v3(brush_color_rgb, brush_color_rgb);
const std::optional<BrushColorJitterSettings> color_jitter_settings =
BKE_brush_color_jitter_get_settings(&paint, &brush);
if (color_jitter_settings) {

View File

@@ -210,11 +210,7 @@ template<typename ImageBuffer> class PaintingKernel {
return;
}
/* NOTE: Brush colors are stored in sRGB. We use math color to follow other areas that
* use brush colors. From there on we use IMB_colormanagement to convert the brush color to the
* colorspace of the texture. This isn't ideal, but would need more refactoring to make sure
* that brush colors are stored in scene linear by default. */
srgb_to_linearrgb_v3_v3(brush_color_, in_brush_color);
copy_v3_v3(brush_color_, in_brush_color);
brush_color_[3] = 1.0f;
const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(

View File

@@ -139,5 +139,4 @@ inline void interpolate_cubic_mitchell_byte(const ImBuf *in, uchar output[4], fl
/**
* Sample pixel of image using NEAREST method.
*/
void IMB_sampleImageAtLocation(
ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, float scene_linear_rgb[3]);

View File

@@ -28,6 +28,7 @@ extern blender::float3x3 imbuf_scene_linear_to_aces;
extern blender::float3x3 imbuf_aces_to_scene_linear;
extern blender::float3x3 imbuf_scene_linear_to_rec709;
extern blender::float3x3 imbuf_rec709_to_scene_linear;
extern bool imbuf_scene_linear_is_rec709;
#define MAX_COLORSPACE_NAME 64

View File

@@ -98,6 +98,7 @@ float3x3 imbuf_scene_linear_to_rec709 = float3x3::zero();
float3x3 imbuf_rec709_to_scene_linear = float3x3::zero();
float3x3 imbuf_scene_linear_to_aces = float3x3::zero();
float3x3 imbuf_aces_to_scene_linear = float3x3::zero();
bool imbuf_scene_linear_is_rec709 = false;
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
@@ -571,6 +572,9 @@ static bool colormanage_load_config(ocio::Config &config)
imbuf_aces_to_scene_linear = imbuf_xyz_to_scene_linear * ocio::ACES_TO_XYZ;
imbuf_scene_linear_to_aces = math::invert(imbuf_aces_to_scene_linear);
imbuf_scene_linear_is_rec709 = math::is_equal(
imbuf_scene_linear_to_rec709, float3x3::identity(), 0.0001f);
return ok;
}

View File

@@ -47,24 +47,41 @@ void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_lin
void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
{
mul_v3_m3v3(scene_linear, imbuf_rec709_to_scene_linear.ptr(), rec709);
if (imbuf_scene_linear_is_rec709) {
copy_v3_v3(scene_linear, rec709);
}
else {
mul_v3_m3v3(scene_linear, imbuf_rec709_to_scene_linear.ptr(), rec709);
}
}
void IMB_colormanagement_scene_linear_to_rec709(float rec709[3], const float scene_linear[3])
{
mul_v3_m3v3(rec709, imbuf_scene_linear_to_rec709.ptr(), scene_linear);
if (imbuf_scene_linear_is_rec709) {
copy_v3_v3(rec709, scene_linear);
}
else {
mul_v3_m3v3(rec709, imbuf_scene_linear_to_rec709.ptr(), scene_linear);
}
}
void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
{
mul_v3_m3v3(srgb, imbuf_scene_linear_to_rec709.ptr(), scene_linear);
if (imbuf_scene_linear_is_rec709) {
copy_v3_v3(srgb, scene_linear);
}
else {
mul_v3_m3v3(srgb, imbuf_scene_linear_to_rec709.ptr(), scene_linear);
}
linearrgb_to_srgb_v3_v3(srgb, srgb);
}
void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
{
srgb_to_linearrgb_v3_v3(scene_linear, srgb);
mul_m3_v3(imbuf_rec709_to_scene_linear.ptr(), scene_linear);
if (!imbuf_scene_linear_is_rec709) {
mul_m3_v3(imbuf_rec709_to_scene_linear.ptr(), scene_linear);
}
}
void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3], const float aces[3])

View File

@@ -6,21 +6,24 @@
* \ingroup imbuf
*/
#include "BLI_math_color.h"
#include "IMB_colormanagement.hh"
#include "IMB_interp.hh"
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, float scene_linear_rgb[3])
{
using namespace blender;
if (ibuf->float_buffer.data) {
imbuf::interpolate_nearest_border_fl(ibuf, color, x, y);
float rgba[4];
imbuf::interpolate_nearest_border_fl(ibuf, rgba, x, y);
premul_to_straight_v4_v4(rgba, rgba);
copy_v3_v3(scene_linear_rgb, rgba);
}
else {
uchar4 byte_color = imbuf::interpolate_nearest_border_byte(ibuf, x, y);
rgba_uchar_to_float(color, byte_color);
if (make_linear_rgb) {
IMB_colormanagement_colorspace_to_scene_linear_v4(
color, false, ibuf->byte_buffer.colorspace);
}
rgb_uchar_to_float(scene_linear_rgb, byte_color);
IMB_colormanagement_colorspace_to_scene_linear_v3(scene_linear_rgb,
ibuf->byte_buffer.colorspace);
}
}

View File

@@ -48,9 +48,12 @@
.fill_threshold = 0.2f, \
\
/* BRUSH PAINT BRUSH SETTINGS */ \
/* Default rgb color of the brush when painting - white. */ \
/* Default rgb color of the brush when painting - white. Initialize both
* linear and deprecated sRGB values. */ \
.color = {1.0f, 1.0f, 1.0f}, \
.rgb = {1.0f, 1.0f, 1.0f}, \
\
.secondary_color = {0, 0, 0}, \
.secondary_rgb = {0, 0, 0}, \
\
/* BRUSH STROKE SETTINGS */ \

View File

@@ -219,7 +219,7 @@ typedef struct Brush {
float rate;
/** Color. */
float rgb[3];
float color[3];
int color_jitter_flag;
float hsv_jitter[3];
@@ -248,7 +248,11 @@ typedef struct Brush {
float tip_scale_x;
/** Background color. */
float secondary_rgb[3];
float secondary_color[3];
/* Deprecated sRGB color for forward compatibility. */
float rgb[3] DNA_DEPRECATED;
float secondary_rgb[3] DNA_DEPRECATED;
/** Rate */
float dash_ratio;
@@ -419,6 +423,8 @@ typedef struct Brush {
} Brush;
/* Struct to hold palette colors for sorting. */
#
#
typedef struct tPaletteColorHSV {
float rgb[3];
float value;
@@ -429,9 +435,13 @@ typedef struct tPaletteColorHSV {
typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
float rgb[3];
/* Two values, one to store color, other to store values for sculpt/weight. */
float color[3];
float value;
/* For forward compatibility. */
float rgb[3] DNA_DEPRECATED;
float _pad;
} PaletteColor;
typedef struct Palette {

View File

@@ -305,6 +305,8 @@
.unprojected_radius = 0.29, \
.alpha = 0.5f, \
.weight = 0.5f, \
.color = {0.0f, 0.0f, 0.0f}, \
.secondary_color = {1.0f, 1.0f, 1.0f}, \
.rgb = {0.0f, 0.0f, 0.0f}, \
.secondary_rgb = {1.0f, 1.0f, 1.0f}, \
.flag = UNIFIED_PAINT_SIZE | UNIFIED_PAINT_COLOR, \

View File

@@ -1075,6 +1075,8 @@ typedef struct TimeMarker {
* values are used
*/
typedef struct UnifiedPaintSettings {
DNA_DEFINE_CXX_METHODS(UnifiedPaintSettings)
/** Unified radius of brush in pixels. */
int size;
@@ -1088,9 +1090,13 @@ typedef struct UnifiedPaintSettings {
float weight;
/** Unified brush color. */
float rgb[3];
float color[3];
/** Unified brush secondary color. */
float secondary_rgb[3];
float secondary_color[3];
/* Deprecated sRGB color for forward compatibility. */
float rgb[3] DNA_DEPRECATED;
float secondary_rgb[3] DNA_DEPRECATED;
/** Unified color jitter settings */
int color_jitter_flag;
@@ -1152,6 +1158,8 @@ typedef struct ToolSystemBrushBindings {
/** Paint Tool Base. */
typedef struct Paint {
DNA_DEFINE_CXX_METHODS(Paint)
/**
* The active brush. Possibly null. Possibly stored in a separate #Main data-base and not user-
* counted.
@@ -1302,6 +1310,8 @@ typedef struct ParticleEditSettings {
/** Sculpt. */
typedef struct Sculpt {
DNA_DEFINE_CXX_METHODS(Sculpt)
Paint paint;
/** For rotating around a pivot point. */
@@ -1646,6 +1656,8 @@ enum {
};
typedef struct ToolSettings {
DNA_DEFINE_CXX_METHODS(ToolSettings)
/** Vertex paint. */
VPaint *vpaint;
/** Weight paint. */

View File

@@ -664,6 +664,13 @@ static void rna_Brush_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *pt
// WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr);
}
static void rna_Brush_color_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Brush *br = static_cast<Brush *>(ptr->data);
rna_Brush_update(bmain, scene, ptr);
BKE_brush_color_sync_legacy(br);
}
static void rna_Brush_material_update(bContext * /*C*/, PointerRNA *ptr)
{
Brush *br = static_cast<Brush *>(ptr->data);
@@ -2824,17 +2831,17 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rate", "Interval between paints for Airbrush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
RNA_def_property_float_sdna(prop, nullptr, "rgb");
RNA_def_property_float_sdna(prop, nullptr, "color");
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
RNA_def_property_update(prop, 0, "rna_Brush_color_update");
prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA);
prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
RNA_def_property_float_sdna(prop, nullptr, "secondary_rgb");
RNA_def_property_float_sdna(prop, nullptr, "secondary_color");
RNA_def_property_ui_text(prop, "Secondary Color", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
RNA_def_property_update(prop, 0, "rna_Brush_color_update");
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);

View File

@@ -18,6 +18,8 @@
# include "DNA_brush_types.h"
# include "BLI_math_color.h"
# include "BKE_library.hh"
# include "BKE_paint.hh"
# include "BKE_report.hh"
@@ -60,6 +62,13 @@ static void rna_Palette_color_clear(Palette *palette)
BKE_palette_clear(palette);
}
static void rna_PaletteColor_color_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
{
/* For forward compatibility. */
PaletteColor *color = static_cast<PaletteColor *>(ptr->data);
BKE_palette_color_sync_legacy(color);
}
static PointerRNA rna_Palette_active_color_get(PointerRNA *ptr)
{
Palette *palette = static_cast<Palette *>(ptr->data);
@@ -137,13 +146,13 @@ static void rna_def_palettecolor(BlenderRNA *brna)
srna = RNA_def_struct(brna, "PaletteColor", nullptr);
RNA_def_struct_ui_text(srna, "Palette Color", "");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, nullptr, "rgb");
RNA_def_property_float_sdna(prop, nullptr, "color");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_PaletteColor_color_update");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);

View File

@@ -527,6 +527,13 @@ static void rna_UnifiedPaintSettings_update(bContext *C, PointerRNA * /*ptr*/)
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene);
}
static void rna_UnifiedPaintSettings_color_update(bContext *C, PointerRNA *ptr)
{
UnifiedPaintSettings *ups = static_cast<UnifiedPaintSettings *>(ptr->data);
rna_UnifiedPaintSettings_update(C, ptr);
BKE_brush_color_sync_legacy(ups);
}
static void rna_UnifiedPaintSettings_size_set(PointerRNA *ptr, int value)
{
UnifiedPaintSettings *ups = static_cast<UnifiedPaintSettings *>(ptr->data);
@@ -849,19 +856,19 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Weight", "Weight to assign in vertex groups");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, nullptr, "rgb");
RNA_def_property_float_sdna(prop, nullptr, "color");
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_color_update");
prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA);
prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, nullptr, "secondary_rgb");
RNA_def_property_float_sdna(prop, nullptr, "secondary_color");
RNA_def_property_ui_text(prop, "Secondary Color", "");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_color_update");
prop = RNA_def_property(srna, "use_color_jitter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);