diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 6a8439ffaaa..7887998b90f 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -316,6 +316,9 @@ class RENDER_PT_shading(RenderButtonsPanel, Panel): col = split.column() col.prop(rd, "use_raytrace", text="Ray Tracing") col.prop(rd, "use_color_management") + sub = col.row() + sub.active = rd.use_color_management == True + sub.prop(rd, "use_color_unpremultiply") col.prop(rd, "alpha_mode", text="Alpha") diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 354a5265f90..a5c8f5c905d 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -285,6 +285,10 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) break; ibuf->index= index; + if(ima->flag & IMA_CM_PREDIVIDE) + ibuf->flags |= IB_cm_predivide; + else + ibuf->flags &= ~IB_cm_predivide; /* this function accepts link==NULL */ BLI_insertlinkbefore(&ima->ibufs, link, ibuf); @@ -2304,9 +2308,17 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ /* since its possible to access the buffer from the image directly, set the profile [#25073] */ ibuf->profile= (iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) ? IB_PROFILE_LINEAR_RGB : IB_PROFILE_NONE; - ibuf->dither= dither; + if(iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) { + ibuf->flags |= IB_cm_predivide; + ima->flag |= IMA_CM_PREDIVIDE; + } + else { + ibuf->flags &= ~IB_cm_predivide; + ima->flag &= ~IMA_CM_PREDIVIDE; + } + ima->ok= IMA_OK_LOADED; return ibuf; diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index cd3d87a8979..33e9192a23e 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -136,13 +136,8 @@ void glaDrawPixelsSafe (float x, float y, int img_w, int img_h, int row_w, int * is expected to be in RGBA byte or float format, and the * modelview and projection matrices are assumed to define a * 1-to-1 mapping to screen space. - * @param gamma_correct Optionally gamma correct float sources to sRGB for display */ - /* only for float rects, converts to 32 bits and draws */ -void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf, int gamma_correct); - - void glaDrawPixelsTex (float x, float y, int img_w, int img_h, int format, void *rect); void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index bff93fea067..e4597d6afc3 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -138,11 +138,14 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat rectf+= 4*(rr->rectx*ymin + xmin); rectc= (unsigned char*)(ibuf->rect + ibuf->x*rymin + rxmin); - if(scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)) + if(scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)) { profile_from= IB_PROFILE_LINEAR_RGB; - else + predivide= (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); + } + else { profile_from= IB_PROFILE_SRGB; - predivide= 0; + predivide= 0; + } IMB_buffer_byte_from_float(rectc, rectf, 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index feff1e05d60..86328ca2a64 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -460,12 +460,15 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int Render *re; RenderResult rres; char name[32]; - int do_gamma_correct=0; + int do_gamma_correct=0, do_predivide=0; int offx=0, newx= rect->xmax-rect->xmin, newy= rect->ymax-rect->ymin; if (id && GS(id->name) != ID_TE) { /* exception: don't color manage texture previews - show the raw values */ - if (sce) do_gamma_correct = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT; + if (sce) { + do_gamma_correct = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT; + do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE; + } } if(!split || first) sprintf(name, "Preview %p", (void *)sa); @@ -488,10 +491,28 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int if(rres.rectf) { if(ABS(rres.rectx-newx)<2 && ABS(rres.recty-newy)<2) { + newrect->xmax= MAX2(newrect->xmax, rect->xmin + rres.rectx + offx); newrect->ymax= MAX2(newrect->ymax, rect->ymin + rres.recty); - glaDrawPixelsSafe_to32(rect->xmin+offx, rect->ymin, rres.rectx, rres.recty, rres.rectx, rres.rectf, do_gamma_correct); + if(rres.rectx && rres.recty) { + /* temporary conversion to byte for drawing */ + float fx= rect->xmin + offx; + float fy= rect->ymin; + int profile_from= (do_gamma_correct)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; + int dither= 0; + unsigned char *rect_byte; + + rect_byte= MEM_mallocN(rres.rectx*rres.recty*sizeof(int), "ed_preview_draw_rect"); + + IMB_buffer_byte_from_float(rect_byte, rres.rectf, + 4, dither, IB_PROFILE_SRGB, profile_from, do_predivide, + rres.rectx, rres.recty, rres.rectx, rres.rectx); + + glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); + + MEM_freeN(rect_byte); + } RE_ReleaseResultImage(re); return 1; diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 8f04940efd6..0b231ee7b96 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -45,9 +45,6 @@ #include "BIF_gl.h" #include "BIF_glutil.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - #ifndef GL_CLAMP_TO_EDGE #define GL_CLAMP_TO_EDGE 0x812F #endif @@ -562,27 +559,6 @@ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void * glaDrawPixelsTexScaled(x, y, img_w, img_h, format, rect, 1.0f, 1.0f); } -/* row_w is unused but kept for completeness */ -void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int UNUSED(row_w), float *rectf, int do_gamma_correct) -{ - unsigned char *rect32; - int profile_from= (do_gamma_correct)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= 0; - - /* copy imgw-imgh to a temporal 32 bits rect */ - if(img_w<1 || img_h<1) return; - - rect32= MEM_mallocN(img_w*img_h*sizeof(int), "temp 32 bits"); - - IMB_buffer_byte_from_float(rect32, rectf, - 4, 0, IB_PROFILE_SRGB, profile_from, predivide, - img_w, img_h, img_w, img_w); - - glaDrawPixelsSafe(fx, fy, img_w, img_h, img_w, GL_RGBA, GL_UNSIGNED_BYTE, rect32); - - MEM_freeN(rect32); -} - void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect) { float xzoom= glaGetOneFloat(GL_ZOOM_X); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index c647ff3df53..8d8c79386c5 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -750,7 +750,9 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields")); uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(split, &imaptr, "use_premultiply", 0, NULL, ICON_NONE); + row= uiLayoutRow(layout, 0); + uiItemR(row, &imaptr, "use_premultiply", 0, NULL, ICON_NONE); + uiItemR(row, &imaptr, "use_color_unpremultiply", 0, NULL, ICON_NONE); } } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 1a808e8ee5f..9d4c5705bd1 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -248,12 +248,10 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) case NC_IMAGE: if (wmn->action == NA_EDITED) { if(type==NTREE_COMPOSIT) { - Scene *scene= wmn->window->screen->scene; - /* note that nodeUpdateID is already called by BKE_image_signal() on all * scenes so really this is just to know if the images is used in the compo else * painting on images could become very slow when the compositor is open. */ - if(nodeUpdateID(scene->nodetree, wmn->reference)) + if(nodeUpdateID(snode->nodetree, wmn->reference)) ED_area_tag_refresh(sa); } } diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 5ce3d63fe86..adf6f4a143b 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -158,6 +158,7 @@ typedef struct ImBuf { #define IB_tiles (1 << 10) #define IB_tilecache (1 << 11) #define IB_premul (1 << 12) +#define IB_cm_predivide (1 << 13) /* * The bit flag is stored in the ImBuf.ftype variable. diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 8a3f6358c5b..0dfc1852e29 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -453,7 +453,8 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from, void IMB_rect_from_float(struct ImBuf *ibuf) { - int predivide= 0, profile_from; + int predivide= (ibuf->flags & IB_cm_predivide); + int profile_from; /* verify we have a float buffer */ if(ibuf->rect_float==NULL) @@ -485,7 +486,8 @@ void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y { float *rect_float; uchar *rect_byte; - int predivide= 0, profile_from; + int predivide= (ibuf->flags & IB_cm_predivide); + int profile_from; /* verify we have a float buffer */ if(ibuf->rect_float==NULL || buffer==NULL) @@ -521,7 +523,8 @@ void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y void IMB_float_from_rect(struct ImBuf *ibuf) { - int predivide= 0, profile_from; + int predivide= (ibuf->flags & IB_cm_predivide); + int profile_from; /* verify if we byte and float buffers */ if(ibuf->rect==NULL) @@ -546,7 +549,7 @@ void IMB_float_from_rect(struct ImBuf *ibuf) /* no profile conversion */ void IMB_float_from_rect_simple(struct ImBuf *ibuf) { - int predivide= 0; + int predivide= (ibuf->flags & IB_cm_predivide); if(ibuf->rect_float==NULL) imb_addrectfloatImBuf(ibuf); @@ -558,7 +561,8 @@ void IMB_float_from_rect_simple(struct ImBuf *ibuf) void IMB_convert_profile(struct ImBuf *ibuf, int profile) { - int predivide= 0, profile_from, profile_to; + int predivide= (ibuf->flags & IB_cm_predivide); + int profile_from, profile_to; if(ibuf->profile == profile) return; @@ -599,7 +603,8 @@ void IMB_convert_profile(struct ImBuf *ibuf, int profile) * if the return */ float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc) { - int predivide= 0, profile_from, profile_to; + int predivide= (ibuf->flags & IB_cm_predivide); + int profile_from, profile_to; /* determine profiles */ if(ibuf->profile == IB_PROFILE_NONE) diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index fc8807d0f7c..a1b0ab06ecd 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -112,14 +112,14 @@ typedef struct Image { /* **************** IMAGE ********************* */ /* Image.flag */ -#define IMA_FIELDS 1 -#define IMA_STD_FIELD 2 -#define IMA_DO_PREMUL 4 - -#define IMA_REFLECT 16 -#define IMA_NOCOLLECT 32 -#define IMA_DEPRECATED 64 -#define IMA_OLD_PREMUL 128 +#define IMA_FIELDS 1 +#define IMA_STD_FIELD 2 +#define IMA_DO_PREMUL 4 +#define IMA_REFLECT 16 +#define IMA_NOCOLLECT 32 +#define IMA_DEPRECATED 64 +#define IMA_OLD_PREMUL 128 +#define IMA_CM_PREDIVIDE 256 /* Image.tpageflag */ #define IMA_TILES 1 diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index d1ab12433fb..9b49bc53ef3 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1100,7 +1100,8 @@ typedef struct Scene { #define R_ALPHAKEY 2 /* color_mgt_flag */ -#define R_COLOR_MANAGEMENT 1 +#define R_COLOR_MANAGEMENT (1 << 0) +#define R_COLOR_MANAGEMENT_PREDIVIDE (1 << 1) /* subimtype, flag options for imtype */ #define R_OPENEXR_HALF 1 /*deprecated*/ diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 6f6a27abe7c..9e7f4a349e7 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -40,6 +40,7 @@ #include "BKE_image.h" #include "WM_types.h" +#include "WM_api.h" static EnumPropertyItem image_source_items[]= { {IMA_SRC_FILE, "FILE", 0, "Single Image", "Single image file"}, @@ -110,6 +111,7 @@ static void rna_Image_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P { Image *ima= ptr->id.data; BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + WM_main_add_notifier(NC_IMAGE|NA_EDITED, &ima->id); DAG_id_tag_update(&ima->id, 0); } @@ -475,6 +477,11 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DO_PREMUL); RNA_def_property_ui_text(prop, "Premultiply", "Convert RGB from key alpha to premultiplied alpha"); RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_reload_update"); + + prop= RNA_def_property(srna, "use_color_unpremultiply", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_CM_PREDIVIDE); + RNA_def_property_ui_text(prop, "Color Unpremultiply", "For premultiplied alpha images, do color space conversion on colors without alpha, to avoid fringing for images with light backgrounds"); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_reload_update"); prop= RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 54267725fe2..b69ca64773c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3228,7 +3228,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "color_mgt_flag", R_COLOR_MANAGEMENT); RNA_def_property_ui_text(prop, "Color Management", "Use linear workflow - gamma corrected imaging pipeline"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_RenderSettings_color_management_update"); - + + prop= RNA_def_property(srna, "use_color_unpremultiply", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "color_mgt_flag", R_COLOR_MANAGEMENT_PREDIVIDE); + RNA_def_property_ui_text(prop, "Color Unpremultipy", "For premultiplied alpha render output, do color space conversion on colors without alpha, to avoid fringing on light backgrounds"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "use_file_extension", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXTENSION); diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c index 8aaf1771b68..72037f232ad 100644 --- a/source/blender/nodes/composite/node_composite_util.c +++ b/source/blender/nodes/composite/node_composite_util.c @@ -607,7 +607,7 @@ void generate_preview(void *data, bNode *node, CompBuf *stackbuf) bNodePreview *preview= node->preview; int xsize, ysize; int profile_from= (rd->color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= 0; + int predivide= (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); int dither= 0; unsigned char *rect; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index fd7c87adea2..57b5cec4256 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -62,7 +62,7 @@ static bNodeSocketTemplate cmp_node_rlayers_out[]= { float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc) { float *rect; - int predivide= 0; + int predivide= (ibuf->flags & IB_cm_predivide); *alloc= FALSE; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7713dcffc5c..555d5c12a86 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1154,7 +1154,7 @@ void RE_ResultGet32(Render *re, unsigned int *rect) } else if(rres.rectf) { int profile_from= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= 0; + int predivide= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); int dither= 0; IMB_buffer_byte_from_float((unsigned char*)rect, rres.rectf, @@ -2556,7 +2556,7 @@ static void do_render_seq(Render * re) * render engine delivers */ int profile_to= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; int profile_from= (ibuf->profile == IB_PROFILE_LINEAR_RGB)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= 0; + int predivide= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); if (!rr->rectf) rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf"); @@ -2995,7 +2995,8 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie } } else { - ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.im_format.planes, 0); + int flags = (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE)? IB_cm_predivide: 0; + ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.im_format.planes, flags); /* if not exists, BKE_write_ibuf makes one */ ibuf->rect= (unsigned int *)rres.rect32;