diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_blender_version.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image.c | 24 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_260.c | 1 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 11 | ||||
-rw-r--r-- | source/blender/editors/space_image/image_buttons.c | 10 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 3 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf_types.h | 8 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 35 | ||||
-rw-r--r-- | source/blender/imbuf/intern/divers.c | 17 | ||||
-rw-r--r-- | source/blender/imbuf/intern/readimage.c | 16 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_image_types.h | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_image.c | 27 | ||||
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_tex_image.c | 3 | ||||
-rw-r--r-- | source/blender/render/intern/source/imagetexture.c | 6 |
14 files changed, 115 insertions, 52 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 5d659d63e27..077bbce2264 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 280 -#define BLENDER_SUBVERSION 69 +#define BLENDER_SUBVERSION 70 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index d59ead25396..9960994400f 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -502,6 +502,12 @@ static void image_init_color_management(Image *ima) if (ibuf->flags & IB_alphamode_premul) { ima->alpha_mode = IMA_ALPHA_PREMUL; } + else if (ibuf->flags & IB_alphamode_channel_packed) { + ima->alpha_mode = IMA_ALPHA_CHANNEL_PACKED; + } + else if (ibuf->flags & IB_alphamode_ignore) { + ima->alpha_mode = IMA_ALPHA_IGNORE; + } else { ima->alpha_mode = IMA_ALPHA_STRAIGHT; } @@ -3592,16 +3598,18 @@ static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf)) static int imbuf_alpha_flags_for_image(Image *ima) { - int flag = 0; - - if (ima->flag & IMA_IGNORE_ALPHA) { - flag |= IB_ignore_alpha; - } - else if (ima->alpha_mode == IMA_ALPHA_PREMUL) { - flag |= IB_alphamode_premul; + switch (ima->alpha_mode) { + case IMA_ALPHA_STRAIGHT: + return 0; + case IMA_ALPHA_PREMUL: + return IB_alphamode_premul; + case IMA_ALPHA_CHANNEL_PACKED: + return IB_alphamode_channel_packed; + case IMA_ALPHA_IGNORE: + return IB_alphamode_ignore; } - return flag; + return 0; } /* the number of files will vary according to the stereo format */ diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 77ef27182f2..7b0aab99aea 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -1808,6 +1808,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) Image *image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima); if (image && (image->flag & IMA_DO_PREMUL) == 0) { + const int IMA_IGNORE_ALPHA = (1 << 12); image->flag |= IMA_IGNORE_ALPHA; } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 7ba0eb7b791..13ccc374073 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3450,6 +3450,17 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 280, 70)) { + /* New image alpha modes. */ + LISTBASE_FOREACH (Image *, image, &bmain->images) { + const int IMA_IGNORE_ALPHA = (1 << 12); + if (image->flag & IMA_IGNORE_ALPHA) { + image->alpha_mode = IMA_ALPHA_IGNORE; + image->flag &= ~IMA_IGNORE_ALPHA; + } + } + } + { /* Versioning code until next subversion bump goes here. */ } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 68af854e367..9f429329597 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -42,6 +42,7 @@ #include "RE_pipeline.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -995,10 +996,11 @@ void uiTemplateImage(uiLayout *layout, if (has_alpha) { col = uiLayoutColumn(layout, false); - uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE); - row = uiLayoutRow(col, false); - uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_alpha")); - uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); + uiItemR(col, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); + + /* Alpha mode has no effect for non-color data. */ + bool is_data = IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name); + uiLayoutSetActive(col, !is_data); } if (ima->source == IMA_SRC_MOVIE) { diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 674dc61cd9e..8574f33bce6 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -476,6 +476,9 @@ int imb_get_anim_type(const char *name); */ bool IMB_isfloat(struct ImBuf *ibuf); +/* Do byte/float and colorspace conversions need to take alpha into account? */ +bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf); + /* create char buffer, color corrected if necessary, for ImBufs that lack one */ void IMB_rect_from_float(struct ImBuf *ibuf); void IMB_float_from_rect(struct ImBuf *ibuf); diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 0f2529e261a..61aa1f401a0 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -285,10 +285,12 @@ enum { IB_alphamode_premul = 1 << 12, /** if this flag is set, alpha mode would be guessed from file */ IB_alphamode_detect = 1 << 13, + /* alpha channel is unrelated to RGB and should not affect it */ + IB_alphamode_channel_packed = 1 << 14, /** ignore alpha on load and substitute it with 1.0f */ - IB_ignore_alpha = 1 << 14, - IB_thumbnail = 1 << 15, - IB_multiview = 1 << 16, + IB_alphamode_ignore = 1 << 15, + IB_thumbnail = 1 << 16, + IB_multiview = 1 << 17, }; /** \} */ diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index ba0f10446a1..8a10af7e184 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -1057,13 +1057,19 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) if (ibuf->rect_float) { const char *to_colorspace = global_role_scene_linear; + const bool predivide = IMB_alpha_affects_rgb(ibuf); if (ibuf->rect) { imb_freerectImBuf(ibuf); } - IMB_colormanagement_transform( - ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true); + IMB_colormanagement_transform(ibuf->rect_float, + ibuf->x, + ibuf->y, + ibuf->channels, + from_colorspace, + to_colorspace, + predivide); } } @@ -1405,6 +1411,7 @@ typedef struct DisplayBufferThread { int channels; float dither; bool is_data; + bool predivide; const char *byte_colorspace; const char *float_colorspace; @@ -1469,6 +1476,7 @@ static void display_buffer_init_handle(void *handle_v, handle->channels = channels; handle->dither = dither; handle->is_data = is_data; + handle->predivide = IMB_alpha_affects_rgb(ibuf); handle->byte_colorspace = init_data->byte_colorspace; handle->float_colorspace = init_data->float_colorspace; @@ -1486,6 +1494,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, bool is_data = handle->is_data; bool is_data_display = handle->cm_processor->is_data_result; + bool predivide = handle->predivide; if (!handle->buffer) { unsigned char *byte_buffer = handle->byte_buffer; @@ -1534,7 +1543,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, if (!is_data && !is_data_display) { IMB_colormanagement_transform( - linear_buffer, width, height, channels, from_colorspace, to_colorspace, true); + linear_buffer, width, height, channels, from_colorspace, to_colorspace, predivide); } *is_straight_alpha = false; @@ -1590,13 +1599,13 @@ static void *do_display_buffer_apply_thread(void *handle_v) } } else { - bool is_straight_alpha, predivide; + bool is_straight_alpha; float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float), "color conversion linear buffer"); display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha); - predivide = is_straight_alpha == false; + bool predivide = handle->predivide && (is_straight_alpha == false); if (is_data) { /* special case for data buffers - no color space conversions, @@ -2178,6 +2187,7 @@ void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *out_buffer, /* TODO(brecht): make this multithreaded, or at least process in batches. */ const unsigned char *in_buffer = (unsigned char *)ibuf->rect; + const bool use_premultiply = IMB_alpha_affects_rgb(ibuf); for (int y = 0; y < height; y++) { const size_t in_offset = (offset_y + y) * ibuf->x + offset_x; @@ -2192,11 +2202,13 @@ void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *out_buffer, rgba_uchar_to_float(pixel, in); OCIO_processorApplyRGB(processor, pixel); linearrgb_to_srgb_v3_v3(pixel, pixel); - mul_v3_fl(pixel, pixel[3]); + if (use_premultiply) { + mul_v3_fl(pixel, pixel[3]); + } rgba_float_to_uchar(out, pixel); } } - else { + else if (use_premultiply) { /* Premultiply only. */ for (int x = 0; x < width; x++, in += 4, out += 4) { out[0] = (in[0] * in[3]) >> 8; @@ -2205,6 +2217,15 @@ void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *out_buffer, out[3] = in[3]; } } + else { + /* Copy only. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + } + } } } diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 1e16f0975e2..aa49453d68c 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -96,6 +96,12 @@ MINLINE void float_to_byte_dither_v4( b[3] = unit_float_to_uchar_clamp(f[3]); } +/* Test if colorspace conversions of pixels in buffer need to take into account alpha. */ +bool IMB_alpha_affects_rgb(const ImBuf *ibuf) +{ + return (ibuf->flags & IB_alphamode_channel_packed) == 0; +} + /* float to byte pixels, output 4-channel RGBA */ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, @@ -728,16 +734,19 @@ void IMB_rect_from_float(ImBuf *ibuf) buffer = MEM_dupallocN(ibuf->rect_float); /* first make float buffer in byte space */ + const bool predivide = IMB_alpha_affects_rgb(ibuf); IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, - true); + predivide); /* convert from float's premul alpha to byte's straight alpha */ - IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y); + if (IMB_alpha_affects_rgb(ibuf)) { + IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y); + } /* convert float to byte */ IMB_buffer_byte_from_float((unsigned char *)ibuf->rect, @@ -802,7 +811,9 @@ void IMB_float_from_rect(ImBuf *ibuf) rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, false); /* byte buffer is straight alpha, float should always be premul */ - IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y); + if (IMB_alpha_affects_rgb(ibuf)) { + IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y); + } if (ibuf->rect_float == NULL) { ibuf->rect_float = rect_float; diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index 9297227bc87..d9f3c7ec6bb 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -61,20 +61,16 @@ static void imb_handle_alpha(ImBuf *ibuf, } bool is_data = (colorspace && IMB_colormanagement_space_name_is_data(colorspace)); - int alpha_flags; + int alpha_flags = (flags & IB_alphamode_detect) ? ibuf->flags : flags; - if (flags & IB_alphamode_detect) { - alpha_flags = ibuf->flags & IB_alphamode_premul; - } - else { - alpha_flags = flags & IB_alphamode_premul; - } - - if (is_data) { + if (is_data || (flags & IB_alphamode_channel_packed)) { /* Don't touch alpha. */ + ibuf->flags |= IB_alphamode_channel_packed; } - else if (flags & IB_ignore_alpha) { + else if (flags & IB_alphamode_ignore) { + /* Make opaque. */ IMB_rectfill_alpha(ibuf, 1.0f); + ibuf->flags |= IB_alphamode_ignore; } else { if (alpha_flags & IB_alphamode_premul) { diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 3e42aa17492..6141472125f 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -178,7 +178,7 @@ enum { /** For image user, but these flags are mixed. */ IMA_USER_FRAME_IN_RANGE = (1 << 10), IMA_VIEW_AS_RENDER = (1 << 11), - IMA_IGNORE_ALPHA = (1 << 12), + IMA_FLAG_UNUSED_12 = (1 << 12), /* cleared */ IMA_DEINTERLACE = (1 << 13), IMA_USE_VIEWS = (1 << 14), IMA_FLAG_UNUSED_15 = (1 << 15), /* cleared */ @@ -233,6 +233,8 @@ enum { enum { IMA_ALPHA_STRAIGHT = 0, IMA_ALPHA_PREMUL = 1, + IMA_ALPHA_CHANNEL_PACKED = 2, + IMA_ALPHA_IGNORE = 3, }; #endif diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 40c8c7e1582..c033e393625 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -680,12 +680,26 @@ static void rna_def_image(BlenderRNA *brna) "STRAIGHT", 0, "Straight", - "Transparent RGB and alpha pixels are unmodified"}, + "Store RGB and alpha channels separately with alpha acting as a mask, also known as " + "unassociated alpha. Commonly used by image editing applications and file formats like " + "PNG"}, {IMA_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", - "Transparent RGB pixels are multiplied by the alpha channel"}, + "Store RGB channels with alpha multipled in, also known as associated alpha. The natural " + "format for renders and used by file formats like OpenEXR"}, + {IMA_ALPHA_CHANNEL_PACKED, + "CHANNEL_PACKED", + 0, + "Channel Packed", + "Different images are packed in the RGB and alpha channels, and they should not " + "affect each other. Channel packing is commonly used by game engines to save memory"}, + {IMA_ALPHA_IGNORE, + "NONE", + 0, + "None", + "Ignore alpha channel from the file and make image fully opaque"}, {0, NULL, 0, NULL, NULL}, }; @@ -744,15 +758,6 @@ static void rna_def_image(BlenderRNA *brna) "Apply render part of display transformation when displaying this image on the screen"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); - prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA); - RNA_def_property_ui_text( - prop, - "Use Alpha", - "Use the alpha channel information from the image or make image fully opaque"); - RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); - prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index 8086bb2e15d..786386bb63e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -184,7 +184,8 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, * that if we blend the color with a transparent shader using alpha as * a factor, we don't multiply alpha into the color twice. */ if (out[1].hasoutput && - !IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) { + !(ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || + IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name))) { GPU_link(mat, "tex_color_alpha_unpremultiply", out[0].link, &out[0].link); } else { diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index c147794dae7..1aa16dc1019 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -233,7 +233,7 @@ int imagewrap(Tex *tex, /* keep this before interpolation [#29761] */ if (ima) { - if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { + if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { texres->talpha = true; } @@ -1056,7 +1056,7 @@ static int imagewraposa_aniso(Tex *tex, image_mipmap_test(tex, ibuf); if (ima) { - if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { + if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { texres->talpha = 1; } @@ -1512,7 +1512,7 @@ int imagewraposa(Tex *tex, image_mipmap_test(tex, ibuf); if (ima) { - if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { + if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { texres->talpha = true; } |