Fix T58549, T56741: HSV color picker issues with Filmic view transform.

In 2d655d3 the color picker was changed to use display space HSV values.
This works ok for a simple sRGB EOTF, but fails with view transforms like
Filmic where display space V 1.0 maps to RGB 16.292.

Instead we now use the color_picking role from the OCIO config when
converting from RGB to HSV in the color picker. This role is set to sRGB
in the default OCIO config.

This color space fits the following requirements:

* It is approximately perceptually linear, so that the HSV numbers and
  the HSV cube/circle have an intuitive distribution.
* It has the same gamut as the scene linear color space.
* Color picking values 0..1 map to scene linear values in the 0..1 range,
  so that picked albedo values are energy conserving.
This commit is contained in:
Brecht Van Lommel 2018-12-13 15:59:58 +01:00
parent 33993c056a
commit 6601a89650
Notes: blender-bot 2023-02-14 05:19:55 +01:00
Referenced by issue #58549, Color input adjusts more than one HSV field
Referenced by issue #56741, Color Picker Value Bug
9 changed files with 199 additions and 175 deletions

View File

@ -34,7 +34,7 @@ roles:
default_sequencer: sRGB
# Color spaces for color picking and texture painting (not internally supported yet)
color_picking: Raw
color_picking: sRGB
texture_paint: Raw
# Non-color data

View File

@ -2992,19 +2992,20 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
block->evil_C = (void *)C; /* XXX */
if (scn) {
block->color_profile = true;
/* store display device name, don't lookup for transformations yet
* block could be used for non-color displays where looking up for transformation
* would slow down redraw, so only lookup for actual transform when it's indeed
* needed
*/
BLI_strncpy(block->display_device, scn->display_settings.display_device, sizeof(block->display_device));
STRNCPY(block->display_device, scn->display_settings.display_device);
/* copy to avoid crash when scene gets deleted with ui still open */
block->unit = MEM_mallocN(sizeof(scn->unit), "UI UnitSettings");
memcpy(block->unit, &scn->unit, sizeof(scn->unit));
}
else {
STRNCPY(block->display_device, IMB_colormanagement_display_get_default_name());
}
BLI_strncpy(block->name, name, sizeof(block->name));
@ -3295,20 +3296,6 @@ void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3])
IMB_colormanagement_display_to_scene_linear_v3(pixel, display);
}
void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max)
{
struct ColorManagedDisplay *display = ui_block_cm_display_get(block);
float pixel[3];
copy_v3_fl(pixel, *min);
IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
*min = min_fff(UNPACK3(pixel));
copy_v3_fl(pixel, *max);
IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
*max = max_fff(UNPACK3(pixel));
}
static uiBut *ui_but_alloc(const eButType type)
{
switch (type) {

View File

@ -1404,15 +1404,12 @@ static void ui_draw_colorband_handle(
void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
{
struct ColorManagedDisplay *display = NULL;
struct ColorManagedDisplay *display = ui_block_cm_display_get(but->block);
uint pos_id, col_id;
ColorBand *coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
if (coba == NULL) return;
if (but->block->color_profile)
display = ui_block_cm_display_get(but->block);
float x1 = rect->xmin;
float sizex = rect->xmax - x1;
float sizey = BLI_rcti_size_y(rect);

View File

@ -5440,7 +5440,6 @@ static bool ui_numedit_but_HSVCUBE(
float x, y;
float mx_fl, my_fl;
bool changed = true;
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
@ -5454,9 +5453,7 @@ static bool ui_numedit_but_HSVCUBE(
#endif
ui_but_v3_get(but, rgb);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(but, rgb, hsv);
@ -5469,8 +5466,7 @@ static bool ui_numedit_but_HSVCUBE(
/* calculate original hsv again */
copy_v3_v3(rgb, data->origvec);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
copy_v3_v3(hsvo, hsv);
@ -5518,9 +5514,6 @@ static bool ui_numedit_but_HSVCUBE(
{
/* vertical 'value' strip */
float min = but->softmin, max = but->softmax;
if (use_display_colorspace) {
ui_block_cm_to_display_space_range(but->block, &min, &max);
}
/* exception only for value strip - use the range set in but->min/max */
hsv[2] = y * (max - min) + min;
break;
@ -5537,9 +5530,7 @@ static bool ui_numedit_but_HSVCUBE(
}
ui_color_picker_to_rgb_HSVCUBE_v(but, hsv, rgb);
if (use_display_colorspace)
ui_block_cm_to_scene_linear_v3(but->block, rgb);
ui_color_picker_to_scene_linear_space(but, rgb);
/* clamp because with color conversion we can exceed range [#34295] */
if (but->a1 == UI_GRAD_V_ALT) {
@ -5565,13 +5556,9 @@ static void ui_ndofedit_but_HSVCUBE(
const float hsv_v_max = max_ff(hsv[2], but->softmax);
float rgb[3];
float sensitivity = (shift ? 0.15f : 0.3f) * ndof->dt;
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_but_v3_get(but, rgb);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(but, rgb, hsv);
switch ((int)but->a1) {
@ -5620,9 +5607,7 @@ static void ui_ndofedit_but_HSVCUBE(
hsv_clamp_v(hsv, hsv_v_max);
ui_color_picker_to_rgb_HSVCUBE_v(but, hsv, rgb);
if (use_display_colorspace)
ui_block_cm_to_scene_linear_v3(but->block, rgb);
ui_color_picker_to_scene_linear_space(but, rgb);
copy_v3_v3(data->vec, rgb);
ui_but_v3_set(but, data->vec);
@ -5737,7 +5722,6 @@ static bool ui_numedit_but_HSVCIRCLE(
float rgb[3];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
@ -5760,9 +5744,7 @@ static bool ui_numedit_but_HSVCIRCLE(
BLI_rcti_rctf_copy(&rect, &but->rect);
ui_but_v3_get(but, rgb);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
/* exception, when using color wheel in 'locked' value state:
@ -5784,9 +5766,7 @@ static bool ui_numedit_but_HSVCIRCLE(
/* calculate original hsv again */
copy_v3_v3(hsvo, hsv);
copy_v3_v3(rgbo, data->origvec);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgbo);
ui_scene_linear_to_color_picker_space(but, rgbo);
ui_rgb_to_color_picker_compat_v(rgbo, hsvo);
/* and original position */
@ -5812,9 +5792,7 @@ static bool ui_numedit_but_HSVCIRCLE(
normalize_v3_length(rgb, but->a2);
}
if (use_display_colorspace)
ui_block_cm_to_scene_linear_v3(but->block, rgb);
ui_color_picker_to_scene_linear_space(but, rgb);
ui_but_v3_set(but, rgb);
data->draglastx = mx;
@ -5831,14 +5809,12 @@ static void ui_ndofedit_but_HSVCIRCLE(
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
float rgb[3];
float phi, r /*, sqr */ /* UNUSED */, v[2];
float sensitivity = (shift ? 0.06f : 0.3f) * ndof->dt;
ui_but_v3_get(but, rgb);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
/* Convert current color on hue/sat disc to circular coordinates phi, r */
@ -5889,9 +5865,7 @@ static void ui_ndofedit_but_HSVCIRCLE(
normalize_v3_length(data->vec, but->a2);
}
if (use_display_colorspace)
ui_block_cm_to_scene_linear_v3(but->block, data->vec);
ui_color_picker_to_scene_linear_space(but, data->vec);
ui_but_v3_set(but, data->vec);
}
#endif /* WITH_INPUT_NDOF */

View File

@ -439,7 +439,7 @@ struct uiBlock {
struct UnitSettings *unit; /* unit system, used a lot for numeric buttons so include here rather then fetching through the scene every time. */
ColorPickerData color_pickers; /* XXX, only accessed by color picker templates */
bool color_profile; /* color profile for correcting linear colors for display */
bool is_color_gamma_picker; /* Block for color picker with gamma baked in. */
char display_device[64]; /* display device name used to display this block,
* used by color widgets to transform colors from/to scene linear
@ -477,7 +477,6 @@ extern void ui_hsvcircle_vals_from_pos(
const float mx, const float my);
extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xpos, float *ypos);
extern void ui_hsvcube_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp);
bool ui_but_is_colorpicker_display_space(struct uiBut *but);
extern void ui_but_string_get_ex(
uiBut *but, char *str, const size_t maxlen,
@ -516,7 +515,6 @@ extern void ui_block_bounds_calc(uiBlock *block);
extern struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block);
void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]);
void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3]);
void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max);
/* interface_regions.c */
@ -611,6 +609,11 @@ void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]);
void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]);
void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b);
bool ui_but_is_color_gamma(uiBut *but);
void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]);
void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]);
uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, void *arg_but);
ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);

View File

@ -111,6 +111,36 @@ void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, flo
}
}
/* Returns true if the button is for a color with gamma baked in,
* or if it's a color picker for such a button. */
bool ui_but_is_color_gamma(uiBut *but)
{
if (but->rnaprop) {
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
return true;
}
}
return but->block->is_color_gamma_picker;
}
void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3])
{
/* Map to color picking space for HSV values and HSV cube/circle,
* assuming it is more perceptually linear then the scene linear
* space for intuitive color picking. */
if (!ui_but_is_color_gamma(but)) {
IMB_colormanagement_scene_linear_to_color_picking_v3(rgb);
}
}
void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3])
{
if (!ui_but_is_color_gamma(but)) {
IMB_colormanagement_color_picking_to_scene_linear_v3(rgb);
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -132,28 +162,18 @@ void ui_but_hsv_set(uiBut *but)
/* Updates all buttons who share the same color picker as the one passed
* also used by small picker, be careful with name checks below... */
static void ui_update_color_picker_buts_rgb(
uiBlock *block, ColorPicker *cpicker, const float rgb[3], bool is_display_space)
uiBut *from_but, uiBlock *block, ColorPicker *cpicker, const float rgb[3])
{
uiBut *bt;
float *hsv = cpicker->color_data;
struct ColorManagedDisplay *display = NULL;
/* this is to keep the H and S value when V is equal to zero
* and we are working in HSV mode, of course!
*/
if (is_display_space) {
ui_rgb_to_color_picker_compat_v(rgb, hsv);
}
else {
/* we need to convert to display space to use hsv, because hsv is stored in display space */
float rgb_display[3];
copy_v3_v3(rgb_display, rgb);
ui_block_cm_to_display_space_v3(block, rgb_display);
ui_rgb_to_color_picker_compat_v(rgb_display, hsv);
/* Convert from RGB to HSV in perceptually linear space. */
float tmp[3];
copy_v3_v3(tmp, rgb);
if (from_but) {
ui_scene_linear_to_color_picker_space(from_but, tmp);
}
if (block->color_profile)
display = ui_block_cm_display_get(block);
ui_rgb_to_color_picker_compat_v(tmp, hsv);
/* this updates button strings, is hackish... but button pointers are on stack of caller function */
for (bt = block->buttons.first; bt; bt = bt->next) {
@ -177,9 +197,9 @@ static void ui_update_color_picker_buts_rgb(
copy_v3_v3(rgb_gamma, rgb);
if (display) {
if (!block->is_color_gamma_picker) {
/* make a display version, for Hex code */
IMB_colormanagement_scene_linear_to_display_v3(rgb_gamma, display);
ui_block_cm_to_display_space_v3(block, rgb_gamma);
}
if (rgb_gamma[0] > 1.0f) rgb_gamma[0] = modf(rgb_gamma[0], &intpart);
@ -230,7 +250,7 @@ static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(a
if (prop) {
RNA_property_float_get_array(&ptr, prop, rgb);
ui_update_color_picker_buts_rgb(
but->block, but->custom_data, rgb, (RNA_property_subtype(prop) == PROP_COLOR_GAMMA));
but, but->block, but->custom_data, rgb);
}
if (popup)
@ -244,16 +264,13 @@ static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(a
float rgb[3];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_color_picker_to_rgb_v(hsv, rgb);
/* hsv is saved in display space so convert back */
if (use_display_colorspace) {
ui_block_cm_to_scene_linear_v3(but->block, rgb);
}
/* hsv is saved in perceptually linear space so convert back */
ui_color_picker_to_scene_linear_space(but, rgb);
ui_update_color_picker_buts_rgb(but->block, cpicker, rgb, !use_display_colorspace);
ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb);
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
@ -270,12 +287,12 @@ static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexc
hex_to_rgb(hexcol, rgb, rgb + 1, rgb + 2);
/* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
if (but->block->color_profile) {
if (!but->block->is_color_gamma_picker) {
/* so we need to linearise it for Blender */
ui_block_cm_to_scene_linear_v3(but->block, rgb);
}
ui_update_color_picker_buts_rgb(but->block, cpicker, rgb, false);
ui_update_color_picker_buts_rgb(NULL, but->block, cpicker, rgb);
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
@ -378,37 +395,22 @@ static void ui_colorpicker_square(uiBlock *block, PointerRNA *ptr, PropertyRNA *
/* a HS circle, V slider, rgb/hsv/hex sliders */
static void ui_block_colorpicker(
uiBlock *block, float rgba[4], PointerRNA *ptr, PropertyRNA *prop, bool show_picker)
uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker)
{
static short colormode = 0; /* temp? 0=rgb, 1=hsv, 2=hex */
uiBut *bt;
int width, butwidth;
static char tip[50];
static char hexcol[128];
float rgb_gamma[3];
unsigned char rgb_gamma_uchar[3];
float softmin, softmax, hardmin, hardmax, step, precision;
int yco;
ColorPicker *cpicker = ui_block_colorpicker_create(block);
float *hsv = cpicker->color_data;
PointerRNA *ptr = &from_but->rnapoin;
PropertyRNA *prop = from_but->rnaprop;
width = PICKER_TOTAL_W;
butwidth = width - 1.5f * UI_UNIT_X;
/* existence of profile means storage is in linear color space, with display correction */
/* XXX That tip message is not use anywhere! */
if (!block->color_profile) {
BLI_strncpy(tip, N_("Value in Display Color Space"), sizeof(tip));
copy_v3_v3(rgb_gamma, rgba);
}
else {
BLI_strncpy(tip, N_("Value in Linear RGB Color Space"), sizeof(tip));
/* make a display version, for Hex code */
copy_v3_v3(rgb_gamma, rgba);
ui_block_cm_to_display_space_v3(block, rgb_gamma);
}
/* sneaky way to check for alpha */
rgba[3] = FLT_MAX;
@ -416,6 +418,11 @@ static void ui_block_colorpicker(
RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
RNA_property_float_get_array(ptr, prop, rgba);
float rgb_perceptual[3];
copy_v3_v3(rgb_perceptual, rgba);
ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual);
ui_rgb_to_color_picker_v(rgb_perceptual, hsv);
/* when the softmax isn't defined in the RNA,
* using very large numbers causes sRGB/linear round trip to fail. */
if (softmax == FLT_MAX) {
@ -539,6 +546,19 @@ static void ui_block_colorpicker(
rgba[3] = 1.0f;
}
/* Hex color is in display space. This should actually be sRGB without any view
* transform, as most other applications would expect this. */
float rgb_gamma[3];
unsigned char rgb_gamma_uchar[3];
if (block->is_color_gamma_picker) {
copy_v3_v3(rgb_gamma, rgba);
}
else {
copy_v3_v3(rgb_gamma, rgba);
ui_block_cm_to_display_space_v3(block, rgb_gamma);
}
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((uint), rgb_gamma_uchar, ));
@ -552,8 +572,6 @@ static void ui_block_colorpicker(
block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y,
butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
ui_rgb_to_color_picker_v(rgb_gamma, hsv);
ui_colorpicker_hide_reveal(block, colormode);
}
@ -576,24 +594,18 @@ static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *blo
float rgb[3];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_but_v3_get(but, rgb);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f);
ui_color_picker_to_rgb_v(hsv, rgb);
if (use_display_colorspace)
ui_block_cm_to_scene_linear_v3(block, rgb);
ui_color_picker_to_scene_linear_space(but, rgb);
ui_but_v3_set(but, rgb);
ui_update_color_picker_buts_rgb(block, cpicker, rgb, !use_display_colorspace);
ui_update_color_picker_buts_rgb(but, block, cpicker, rgb);
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
@ -612,8 +624,8 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_
block = UI_block_begin(C, handle->region, __func__, UI_EMBOSS);
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
block->color_profile = false;
if (ui_but_is_color_gamma(but)) {
block->is_color_gamma_picker = true;
}
if (but->block) {
@ -626,7 +638,7 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_
copy_v3_v3(handle->retvec, but->editvec);
ui_block_colorpicker(block, handle->retvec, &but->rnapoin, but->rnaprop, show_picker);
ui_block_colorpicker(block, but, handle->retvec, show_picker);
block->flag = UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT;
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);

View File

@ -2581,23 +2581,16 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
ColorPicker *cpicker = but->custom_data;
const float *hsv_ptr = cpicker->color_data;
float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
bool color_profile = ui_but_is_colorpicker_display_space(but);
float rgb[3], hsv[3], rgb_center[3];
bool is_color_gamma = ui_but_is_color_gamma(but);
/* color */
/* Initialize for compatibility. */
copy_v3_v3(hsv, cpicker->color_data);
/* Compute current hue. */
ui_but_v3_get(but, rgb);
/* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
hsvo[0] = hsv[0] = hsv_ptr[0];
hsvo[1] = hsv[1] = hsv_ptr[1];
hsvo[2] = hsv[2] = hsv_ptr[2];
if (color_profile)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
copy_v3_v3(hsvo, hsv);
CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
@ -2611,7 +2604,13 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
hsv[2] = 0.5f;
}
ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
const float hsv_center[3] = {0.0f, 0.0f, hsv[2]};
ui_color_picker_to_rgb_v(hsv_center, rgb_center);
ui_scene_linear_to_color_picker_space(but, rgb_center);
if (!is_color_gamma) {
ui_block_cm_to_display_space_v3(but->block, rgb_center);
}
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@ -2620,19 +2619,27 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
immBegin(GPU_PRIM_TRI_FAN, tot + 2);
immAttr3fv(color, colcent);
immAttr3fv(color, rgb_center);
immVertex2f(pos, centx, centy);
float ang = 0.0f;
for (int a = 0; a <= tot; a++, ang += radstep) {
float si = sinf(ang);
float co = cosf(ang);
float hsv_ang[3];
float rgb_ang[3];
ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
ui_hsvcircle_vals_from_pos(hsv_ang, hsv_ang + 1, rect, centx + co * radius, centy + si * radius);
hsv_ang[2] = hsv[2];
ui_color_picker_to_rgb_v(hsv, col);
ui_color_picker_to_rgb_v(hsv_ang, rgb_ang);
ui_color_picker_to_scene_linear_space(but, rgb_ang);
immAttr3fv(color, col);
if (!is_color_gamma) {
ui_block_cm_to_display_space_v3(but->block, rgb_ang);
}
immAttr3fv(color, rgb_ang);
immVertex2f(pos, centx + co * radius, centy + si * radius);
}
immEnd();
@ -2656,8 +2663,13 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
GPU_line_smooth(false);
/* cursor */
copy_v3_v3(hsv, cpicker->color_data);
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
float xpos, ypos;
ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos);
ui_hsvcircle_pos_from_vals(but, rect, hsv, &xpos, &ypos);
ui_hsv_cursor(xpos, ypos);
}
@ -2812,18 +2824,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
immUnbindProgram();
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
{
bool color_profile = but->block->color_profile;
if (but->rnaprop) {
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
color_profile = false;
}
return color_profile;
}
void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp)
{
float x = 0.0f, y = 0.0f;
@ -2865,15 +2865,12 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float hsv_n[3];
bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
/* Initialize for compatibility. */
copy_v3_v3(hsv_n, hsv);
ui_but_v3_get(but, rgb);
if (use_display_colorspace)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
rgb_to_hsv_compat_v(rgb, hsv_n);
ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
@ -2901,15 +2898,9 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
const float rad = wcol->roundness * BLI_rcti_size_x(rect);
float x, y;
float rgb[3], hsv[3], v;
bool color_profile = but->block->color_profile;
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
color_profile = false;
ui_but_v3_get(but, rgb);
if (color_profile)
ui_block_cm_to_display_space_v3(but->block, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
if (but->a1 == UI_GRAD_L_ALT)
rgb_to_hsl_v(rgb, hsv);
@ -2920,9 +2911,6 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
/* map v from property range to [0,1] */
if (but->a1 == UI_GRAD_V_ALT) {
float min = but->softmin, max = but->softmax;
if (color_profile) {
ui_block_cm_to_display_space_range(but->block, &min, &max);
}
v = (v - min) / (max - min);
}
@ -3378,16 +3366,12 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
{
uiWidgetBase wtb;
float rad, col[4];
bool color_profile = but->block->color_profile;
col[3] = 1.0f;
if (but->rnaprop) {
BLI_assert(but->rnaindex == -1);
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
color_profile = false;
if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
}
@ -3415,7 +3399,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
round_box_edges(&wtb, roundboxalign, rect, rad);
}
if (color_profile)
if (!ui_but_is_color_gamma(but))
ui_block_cm_to_display_space_v3(but->block, col);
rgba_float_to_uchar((unsigned char *)wcol->inner, col);

View File

@ -96,6 +96,9 @@ void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], struct Co
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, bool predivide);
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], struct ColorManagedDisplay *display);
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], struct ColorManagedDisplay *display);

View File

@ -130,7 +130,14 @@ static struct global_glsl_state {
/* Container for GLSL state needed for OCIO module. */
struct OCIO_GLSLDrawState *ocio_glsl_state;
struct OCIO_GLSLDrawState *transform_ocio_glsl_state;
} global_glsl_state;
} global_glsl_state = {NULL};
static struct global_color_picking_state {
/* Cached processor for color picking conversion. */
OCIO_ConstProcessorRcPtr *processor_to;
OCIO_ConstProcessorRcPtr *processor_from;
bool failed;
} global_color_picking_state = {NULL};
/*********************** Color managed cache *************************/
@ -699,6 +706,15 @@ void colormanagement_exit(void)
if (global_glsl_state.transform_ocio_glsl_state)
OCIO_freeOGLState(global_glsl_state.transform_ocio_glsl_state);
if (global_color_picking_state.processor_to)
OCIO_processorRelease(global_color_picking_state.processor_to);
if (global_color_picking_state.processor_from)
OCIO_processorRelease(global_color_picking_state.processor_from);
memset(&global_glsl_state, 0, sizeof(global_glsl_state));
memset(&global_color_picking_state, 0, sizeof(global_color_picking_state));
colormanage_free_config();
}
@ -1911,6 +1927,54 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in
}
}
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
{
if (!global_color_picking_state.processor_to && !global_color_picking_state.failed) {
/* Create processor if none exists. */
BLI_mutex_lock(&processor_lock);
if (!global_color_picking_state.processor_to && !global_color_picking_state.failed) {
global_color_picking_state.processor_to =
create_colorspace_transform_processor(global_role_scene_linear,
global_role_color_picking);
if (!global_color_picking_state.processor_to) {
global_color_picking_state.failed = true;
}
}
BLI_mutex_unlock(&processor_lock);
}
if (global_color_picking_state.processor_to) {
OCIO_processorApplyRGB(global_color_picking_state.processor_to, pixel);
}
}
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
{
if (!global_color_picking_state.processor_from && !global_color_picking_state.failed) {
/* Create processor if none exists. */
BLI_mutex_lock(&processor_lock);
if (!global_color_picking_state.processor_from && !global_color_picking_state.failed) {
global_color_picking_state.processor_from =
create_colorspace_transform_processor(global_role_color_picking,
global_role_scene_linear);
if (!global_color_picking_state.processor_from) {
global_color_picking_state.failed = true;
}
}
BLI_mutex_unlock(&processor_lock);
}
if (global_color_picking_state.processor_from) {
OCIO_processorApplyRGB(global_color_picking_state.processor_from, pixel);
}
}
/* convert pixel from scene linear to display space using default view
* used by performance-critical areas such as color-related widgets where we want to reduce
* amount of per-widget allocations