Index: release/ui/buttons_scene.py =================================================================== --- release/ui/buttons_scene.py (revision 20771) +++ release/ui/buttons_scene.py (working copy) @@ -21,6 +21,7 @@ sub.itemR(rd, "render_shadows", text="Shadows") sub.itemR(rd, "render_sss", text="Subsurface Scattering") sub.itemR(rd, "render_envmaps", text="Environment Map") + sub.itemR(rd, "color_management") # sub.itemR(rd, "render_radiosity", text="Radio") col = split.column() Index: source/blender/blenkernel/BKE_colortools.h =================================================================== --- source/blender/blenkernel/BKE_colortools.h (revision 20771) +++ source/blender/blenkernel/BKE_colortools.h (working copy) @@ -33,6 +33,11 @@ struct CurveMap; struct ImBuf; struct rctf; + +void gamma_correct_rec709(float *c, float gamma); +void gamma_correct(float *c, float gamma); +float srgb_to_linearrgb(float c); +float linearrgb_to_srgb(float c); struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy); void curvemapping_free(struct CurveMapping *cumap); @@ -60,5 +65,6 @@ void curvemapping_table_RGBA(struct CurveMapping *cumap, float **array, int *size); void colorcorrection_do_ibuf(struct ImBuf *ibuf, const char *profile); + #endif Index: source/blender/blenkernel/intern/colortools.c =================================================================== --- source/blender/blenkernel/intern/colortools.c (revision 20771) +++ source/blender/blenkernel/intern/colortools.c (working copy) @@ -58,6 +58,48 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +/* ********************************* color transforms ********************************* */ + +/*Transform linear RGB values to nonlinear RGB values. Rec. + 709 is ITU-R Recommendation BT. 709 (1990) ``Basic + Parameter Values for the HDTV Standard for the Studio and + for International Programme Exchange'', formerly CCIR Rec. + 709.*/ +void gamma_correct_rec709(float *c, float gamma) +{ + /* Rec. 709 gamma correction. */ + float cc = 0.018f; + + if (*c < cc) + *c *= ((1.099f * (float)pow(cc, gamma)) - 0.099f) / cc; + else + *c = (1.099f * (float)pow(*c, gamma)) - 0.099f; +} + +void gamma_correct(float *c, float gamma) +{ + *c = pow((*c), gamma); +} + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045f) + return (c < 0.f)?0.f:c / 12.92; + else + return pow((c + 0.055)/1.055, 2.4); +} + +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) + return (c < 0.f)?0.f:c * 12.92; + else + return 1.055 * pow(c, 1.0/2.4) - 0.055; +} + + + + /* ********************************* color curve ********************* */ /* ***************** operations on full struct ************* */ Index: source/blender/blenkernel/intern/scene.c =================================================================== --- source/blender/blenkernel/intern/scene.c (revision 20771) +++ source/blender/blenkernel/intern/scene.c (working copy) @@ -228,6 +228,7 @@ sce->r.frs_sec= 25; sce->r.frs_sec_base= 1; sce->r.ocres = 128; + sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT; sce->r.bake_mode= 1; /* prevent to include render stuff here */ sce->r.bake_filter= 2; Index: source/blender/blenlib/BLI_arithb.h =================================================================== --- source/blender/blenlib/BLI_arithb.h (revision 20771) +++ source/blender/blenlib/BLI_arithb.h (working copy) @@ -339,7 +339,6 @@ void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv); void xyz_to_rgb(float x, float y, float z, float *r, float *g, float *b, int colorspace); int constrain_rgb(float *r, float *g, float *b); -void gamma_correct_rgb(float *r, float *g, float *b); unsigned int hsv_to_cpack(float h, float s, float v); unsigned int rgb_to_cpack(float r, float g, float b); void cpack_to_rgb(unsigned int col, float *r, float *g, float *b); Index: source/blender/blenlib/intern/arithb.c =================================================================== --- source/blender/blenlib/intern/arithb.c (revision 20771) +++ source/blender/blenlib/intern/arithb.c (working copy) @@ -3548,30 +3548,7 @@ return 0; /* Colour within RGB gamut */ } -/*Transform linear RGB values to nonlinear RGB values. Rec. - 709 is ITU-R Recommendation BT. 709 (1990) ``Basic - Parameter Values for the HDTV Standard for the Studio and - for International Programme Exchange'', formerly CCIR Rec. - 709.*/ -static void gamma_correct(float *c) -{ - /* Rec. 709 gamma correction. */ - float cc = 0.018f; - - if (*c < cc) - *c *= ((1.099f * (float)pow(cc, 0.45)) - 0.099f) / cc; - else - *c = (1.099f * (float)pow(*c, 0.45)) - 0.099f; -} -void gamma_correct_rgb(float *r, float *g, float *b) -{ - gamma_correct(r); - gamma_correct(g); - gamma_correct(b); -} - - /* we define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so. for that reason it is sensitive for endianness... with this function it works correctly */ Index: source/blender/blenloader/intern/readfile.c =================================================================== --- source/blender/blenloader/intern/readfile.c (revision 20771) +++ source/blender/blenloader/intern/readfile.c (working copy) @@ -8982,11 +8982,22 @@ Mesh *me; Scene *sce; Tex *tx; + SpaceLink *sl; + ScrArea *sa; ParticleSettings *part; for(screen= main->screen.first; screen; screen= screen->id.next) { do_versions_windowmanager_2_50(screen); do_versions_gpencil_2_50(main, screen); + + for(sa= screen->areabase.first; sa; sa= sa->next) { + for(sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_IMAGE) { + SpaceImage *si = (SpaceImage *)sl; + si->flag |= SI_DRAW_CORRECTED; + } + } + } } /* old Animation System (using IPO's) needs to be converted to the new Animato system Index: source/blender/editors/include/BIF_glutil.h =================================================================== --- source/blender/editors/include/BIF_glutil.h (revision 20771) +++ source/blender/editors/include/BIF_glutil.h (working copy) @@ -129,10 +129,11 @@ * 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); +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); Index: source/blender/editors/preview/previewrender.c =================================================================== --- source/blender/editors/preview/previewrender.c (revision 20771) +++ source/blender/editors/preview/previewrender.c (working copy) @@ -326,7 +326,7 @@ sce->world->exp= scene->world->exp; sce->world->range= scene->world->range; } - + sce->r.color_mgt_flag = scene->r.color_mgt_flag; sce->r.cfra= scene->r.cfra; if(id_type==ID_MA) { @@ -387,6 +387,9 @@ sce->lay= 1<r.color_mgt_flag &= ~R_COLOR_MANAGEMENT; + for(base= sce->base.first; base; base= base->next) { if(base->object->id.name[2]=='t') { Material *mat= give_current_material(base->object, base->object->actcol); @@ -453,7 +456,7 @@ ofsy= ri->disprect.ymin + rr->tilerect.ymin; glDrawBuffer(GL_FRONT); - glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf); + glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf, 0); bglFlush(); glDrawBuffer(GL_BACK); } @@ -634,14 +637,22 @@ void ED_preview_draw(const bContext *C, void *idp, rcti *rect) { ScrArea *sa= CTX_wm_area(C); + Scene *sce = CTX_data_scene(C); SpaceButs *sbuts= sa->spacedata.first; + ID *id = (ID *)idp; RenderResult rres; int newx= rect->xmax-rect->xmin, newy= rect->ymax-rect->ymin; int ok= 0; char name[32]; + int gamma_correct=0; + if (id && GS(id->name) != ID_TE) { + /* exception: don't colour manage texture previews - show the raw values */ + if (sce) gamma_correct = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT; + } + sprintf(name, "Preview %p", sa); - BLI_lock_malloc_thread(); +// BLI_lock_malloc_thread(); RE_GetResultImage(RE_GetRender(name), &rres); if(rres.rectf) { @@ -651,7 +662,7 @@ rect->xmax= rect->xmin + rres.rectx; rect->ymax= rect->ymin + rres.recty; - glaDrawPixelsSafe(rect->xmin, rect->ymin, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_FLOAT, rres.rectf); + glaDrawPixelsSafe_to32(rect->xmin, rect->ymin, rres.rectx, rres.recty, rres.rectx, rres.rectf, gamma_correct); ok= 1; } } @@ -692,7 +703,7 @@ glDrawBuffer(GL_FRONT); // glaDefine2DArea(&sa->winrct); - glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf); + glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf, 0); bglFlush(); glDrawBuffer(GL_BACK); Index: source/blender/editors/screen/glutil.c =================================================================== --- source/blender/editors/screen/glutil.c (revision 20771) +++ source/blender/editors/screen/glutil.c (working copy) @@ -482,7 +482,7 @@ glaDrawPixelsTexScaled(x, y, img_w, img_h, format, rect, 1.0f, 1.0f); } -void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf) +void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf, int gamma_correct) { float *rf; int x, y; @@ -493,15 +493,29 @@ rc= rect32= MEM_mallocN(img_w*img_h*sizeof(int), "temp 32 bits"); - for(y=0; yflag |= SI_PREVSPACE; + sima->flag |= SI_DRAW_CORRECTED; } else { /* use any area of decent size */ @@ -2295,6 +2297,7 @@ /* makes ESC go back to prev space */ sima->flag |= SI_PREVSPACE; + sima->flag |= SI_DRAW_CORRECTED; } } } @@ -2422,21 +2425,41 @@ rectf+= 4*(rr->rectx*ymin + xmin); rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin); - for(y1= 0; y1= (char *)(ibuf->rect)) { - for(x1= 0; x1scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) { + for(y1= 0; y1= (char *)(ibuf->rect)) { + for(x1= 0; x1rectx; + rectc += 4*ibuf->x; } - rectf += 4*rr->rectx; - rectc += 4*ibuf->x; + } else { + for(y1= 0; y1= (char *)(ibuf->rect)) { + for(x1= 0; x1rectx; + rectc += 4*ibuf->x; + } } /* make jobs timer to send notifier */ Index: source/blender/editors/space_image/image_draw.c =================================================================== --- source/blender/editors/space_image/image_draw.c (revision 20771) +++ source/blender/editors/space_image/image_draw.c (working copy) @@ -106,7 +106,7 @@ return 0; } -static void image_verify_buffer_float(SpaceImage *sima, ImBuf *ibuf) +static void image_verify_buffer_float(SpaceImage *sima, Image *ima, ImBuf *ibuf, int color_manage) { /* detect if we need to redo the curve map. ibuf->rect is zero for compositor and render results after change @@ -121,6 +121,14 @@ curvemapping_do_ibuf(sima->cumap, ibuf); } else { + if (color_manage) { + if (sima->flag & SI_DRAW_CORRECTED) { + if (ima && ima->source == IMA_SRC_VIEWER) + ibuf->profile = IB_PROFILE_SRGB; + } + } else { + ibuf->profile = IB_PROFILE_NONE; + } IMB_rect_from_float(ibuf); } } @@ -370,9 +378,10 @@ MEM_freeN(rectf); } -static void draw_image_buffer(SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy) +static void draw_image_buffer(SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy) { int x, y; + int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT; /* set zoom */ glPixelZoom(zoomx, zoomy); @@ -397,7 +406,7 @@ } #ifdef WITH_LCMS else if(sima->flag & SI_COLOR_CORRECTION) { - image_verify_buffer_float(sima, ibuf); + image_verify_buffer_float(sima, ima, ibuf, color_manage); sima_draw_colorcorrected_pixels(x, y, ibuf); @@ -413,7 +422,7 @@ /* we don't draw floats buffers directly but * convert them, and optionally apply curves */ - image_verify_buffer_float(sima, ibuf); + image_verify_buffer_float(sima, ima, ibuf, color_manage); if(ibuf->rect) glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); @@ -450,10 +459,12 @@ return rectmain; } -static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Image *ima, ImBuf *ibuf, float zoomx, float zoomy) +static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float zoomx, float zoomy) { unsigned int *rect; int dx, dy, sx, sy, x, y; + int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT; + /* verify valid values, just leave this a while */ if(ima->xrep<1) return; @@ -465,7 +476,7 @@ sima->curtile = ima->xrep*ima->yrep - 1; /* create char buffer from float if needed */ - image_verify_buffer_float(sima, ibuf); + image_verify_buffer_float(sima, ima, ibuf, color_manage); /* retrieve part of image buffer */ dx= ibuf->x/ima->xrep; @@ -488,7 +499,7 @@ MEM_freeN(rect); } -static void draw_image_buffer_repeated(SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float zoomx, float zoomy) +static void draw_image_buffer_repeated(SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float zoomx, float zoomy) { float x, y; double time_current; @@ -497,7 +508,7 @@ for(x=ar->v2d.cur.xmin; xv2d.cur.xmax; x += zoomx) { for(y=ar->v2d.cur.ymin; yv2d.cur.ymax; y += zoomy) { - draw_image_buffer(sima, ar, scene, ibuf, x, y, zoomx, zoomy); + draw_image_buffer(sima, ar, scene, ima, ibuf, x, y, zoomx, zoomy); /* only draw until running out of time */ if((PIL_check_seconds_timer() - time_current) > 0.25) @@ -667,11 +678,11 @@ if(ibuf==NULL) draw_image_grid(ar, zoomx, zoomy); else if(sima->flag & SI_DRAW_TILE) - draw_image_buffer_repeated(sima, ar, scene, ibuf, zoomx, zoomy); + draw_image_buffer_repeated(sima, ar, scene, ima, ibuf, zoomx, zoomy); else if(ima && (ima->tpageflag & IMA_TILES)) - draw_image_buffer_tiled(sima, ar, ima, ibuf, zoomx, zoomy); + draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, zoomx, zoomy); else - draw_image_buffer(sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy); + draw_image_buffer(sima, ar, scene, ima, ibuf, 0.0f, 0.0f, zoomx, zoomy); /* grease pencil */ draw_image_grease_pencil(sima, ibuf); Index: source/blender/editors/space_image/image_header.c =================================================================== --- source/blender/editors/space_image/image_header.c (revision 20771) +++ source/blender/editors/space_image/image_header.c (working copy) @@ -145,6 +145,7 @@ uiItemS(layout); + uiItemR(layout, NULL, 0, &spaceptr, "display_corrected", 0, 0, 0); uiItemR(layout, NULL, 0, &spaceptr, "update_automatically", 0, 0, 0); // XXX if(show_uvedit) uiItemR(layout, NULL, 0, &uvptr, "local_view", 0, 0, 0); // "UV Local View", Numpad / Index: source/blender/editors/space_image/image_render.c =================================================================== --- source/blender/editors/space_image/image_render.c (revision 20771) +++ source/blender/editors/space_image/image_render.c (working copy) @@ -119,7 +119,7 @@ if(rect32) glaDrawPixelsSafe(x1, y1, xmax, ymax, rr->rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect32); else - glaDrawPixelsSafe_to32(x1, y1, xmax, ymax, rr->rectx, rectf); + glaDrawPixelsSafe_to32(x1, y1, xmax, ymax, rr->rectx, rectf, 0); glPixelZoom(1.0, 1.0); Index: source/blender/editors/space_image/space_image.c =================================================================== --- source/blender/editors/space_image/space_image.c (revision 20771) +++ source/blender/editors/space_image/space_image.c (working copy) @@ -113,6 +113,8 @@ simage= MEM_callocN(sizeof(SpaceImage), "initimage"); simage->spacetype= SPACE_IMAGE; simage->zoom= 1; + simage->lock = 1; + simage->flag |= SI_DRAW_CORRECTED; simage->iuser.ok= 1; simage->iuser.fie_ima= 2; @@ -158,7 +160,7 @@ /* spacetype; init callback */ static void image_init(struct wmWindowManager *wm, ScrArea *sa) { - + } static SpaceLink *image_duplicate(SpaceLink *sl) Index: source/blender/imbuf/IMB_imbuf_types.h =================================================================== --- source/blender/imbuf/IMB_imbuf_types.h (revision 20771) +++ source/blender/imbuf/IMB_imbuf_types.h (working copy) @@ -98,9 +98,13 @@ unsigned int encodedsize; /**< Size of data written to encodedbuffer */ unsigned int encodedbuffersize; /**< Size of encodedbuffer */ - float *rect_float; /**< floating point Rect equivalent */ + float *rect_float; /**< floating point Rect equivalent + Linear RGB colour space - may need gamma correction to + sRGB when generating 8bit representations */ int channels; /**< amount of channels in rect_float (0 = 4 channel default) */ float dither; /**< random dither value, for conversion from float -> byte rect */ + short profile; /** colour space/profile preset that the byte rect buffer represents */ + char profile_filename[256]; /** to be implemented properly, specific filename for custom profiles */ struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */ struct ImgInfo * img_info; @@ -213,6 +217,18 @@ #define AN_tanx (Anim | TANX) /**@}*/ +/** + * \name Imbuf preset profile tags + * \brief Some predefined color space profiles that 8 bit imbufs can represent + */ +/**@{*/ +#define IB_PROFILE_NONE 0 +#define IB_PROFILE_LINEAR_RGB 1 +#define IB_PROFILE_SRGB 2 +#define IB_PROFILE_CUSTOM 3 +/**@}*/ + + /** \name Imbuf File Type Tests * \brief These macros test if an ImBuf struct is the corresponding file type. */ Index: source/blender/imbuf/intern/divers.c =================================================================== --- source/blender/imbuf/intern/divers.c (revision 20771) +++ source/blender/imbuf/intern/divers.c (working copy) @@ -39,6 +39,7 @@ #include "IMB_allocimbuf.h" #include "IMB_divers.h" #include "BKE_utildefines.h" +#include "BKE_colortools.h" void imb_checkncols(struct ImBuf *ibuf) { @@ -176,9 +177,10 @@ void IMB_rect_from_float(struct ImBuf *ibuf) { /* quick method to convert floatbuf to byte */ - float *tof = ibuf->rect_float; + float *tof = (float *)ibuf->rect_float; float dither= ibuf->dither; int i, channels= ibuf->channels; + short profile= ibuf->profile; unsigned char *to = (unsigned char *) ibuf->rect; if(tof==NULL) return; @@ -187,7 +189,25 @@ to = (unsigned char *) ibuf->rect; } - if(dither==0.0f || channels!=4) { + if (profile == IB_PROFILE_SRGB && (channels == 3 || channels == 4)) { + if(channels == 3) { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) { + to[0] = FTOCHAR(linearrgb_to_srgb(tof[0])); + to[1] = FTOCHAR(linearrgb_to_srgb(tof[1])); + to[2] = FTOCHAR(linearrgb_to_srgb(tof[2])); + to[3] = 255; + } + } + else if (channels == 4) { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) { + to[0] = FTOCHAR(linearrgb_to_srgb(tof[0])); + to[1] = FTOCHAR(linearrgb_to_srgb(tof[1])); + to[2] = FTOCHAR(linearrgb_to_srgb(tof[2])); + to[3] = FTOCHAR(tof[3]); + } + } + } + else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_LINEAR_RGB) && (dither==0.0f || channels!=4)) { if(channels==1) { for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++) to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]); @@ -242,14 +262,28 @@ tof = ibuf->rect_float; } - for (i = ibuf->x * ibuf->y; i > 0; i--) - { - tof[0] = ((float)to[0])*(1.0f/255.0f); - tof[1] = ((float)to[1])*(1.0f/255.0f); - tof[2] = ((float)to[2])*(1.0f/255.0f); - tof[3] = ((float)to[3])*(1.0f/255.0f); - to += 4; - tof += 4; + if (ibuf->profile == IB_PROFILE_SRGB) { + /* convert from srgb to linear rgb */ + + for (i = ibuf->x * ibuf->y; i > 0; i--) + { + tof[0] = srgb_to_linearrgb(((float)to[0])*(1.0f/255.0f)); + tof[1] = srgb_to_linearrgb(((float)to[1])*(1.0f/255.0f)); + tof[2] = srgb_to_linearrgb(((float)to[2])*(1.0f/255.0f)); + tof[3] = ((float)to[3])*(1.0f/255.0f); + to += 4; + tof += 4; + } + } else { + for (i = ibuf->x * ibuf->y; i > 0; i--) + { + tof[0] = ((float)to[0])*(1.0f/255.0f); + tof[1] = ((float)to[1])*(1.0f/255.0f); + tof[2] = ((float)to[2])*(1.0f/255.0f); + tof[3] = ((float)to[3])*(1.0f/255.0f); + to += 4; + tof += 4; + } } } Index: source/blender/makesdna/DNA_scene_types.h =================================================================== --- source/blender/makesdna/DNA_scene_types.h (revision 20771) +++ source/blender/makesdna/DNA_scene_types.h (working copy) @@ -269,8 +269,12 @@ * Value used to define filter size for all filter options */ float gauss; + + /* color management settings - colour profiles, gamma correction, etc */ + int color_mgt_flag; + /** post-production settings. Depricated, but here for upwards compat (initialized to 1) */ - float postmul, postgamma, posthue, postsat; + float postgamma, posthue, postsat; /* Dither noise intensity */ float dither_intensity; @@ -703,6 +707,9 @@ #define R_PLANES32 32 #define R_PLANESBW 8 +/* color_mgt_flag */ +#define R_COLOR_MANAGEMENT 1 + /* imtype */ #define R_TARGA 0 #define R_IRIS 1 Index: source/blender/makesdna/DNA_space_types.h =================================================================== --- source/blender/makesdna/DNA_space_types.h (revision 20771) +++ source/blender/makesdna/DNA_space_types.h (working copy) @@ -582,7 +582,7 @@ #define SI_DEPRECATED1 1<<4 /* stick UVs to others in the same location */ #define SI_DRAWSHADOW 1<<5 #define SI_SELACTFACE 1<<6 /* deprecated */ -#define SI_DEPRECATED2 1<<7 +#define SI_DRAW_CORRECTED 1<<7 /* image editor uses color profiles to show corrected display */ #define SI_DEPRECATED3 1<<8 /* stick UV selection to mesh vertex (UVs wont always be touching) */ #define SI_COORDFLOATS 1<<9 #define SI_PIXELSNAP 1<<10 Index: source/blender/makesrna/intern/rna_scene.c =================================================================== --- source/blender/makesrna/intern/rna_scene.c (revision 20771) +++ source/blender/makesrna/intern/rna_scene.c (working copy) @@ -589,6 +589,11 @@ RNA_def_property_ui_text(prop, "Do Sequence", "Process the render (and composited) result through the video sequence editor pipeline"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + prop= RNA_def_property(srna, "color_management", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "color_mgt_flag", R_COLOR_MANAGEMENT); + RNA_def_property_ui_text(prop, "Color Management", "Use color profiles and gamma corrected imaging pipeline"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_MATERIAL|ND_SHADING, NULL); + prop= RNA_def_property(srna, "file_extensions", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXTENSION); RNA_def_property_ui_text(prop, "File Extensions", "Add the file format extensions to the rendered file name (eg: filename + .jpg)"); Index: source/blender/makesrna/intern/rna_space.c =================================================================== --- source/blender/makesrna/intern/rna_space.c (revision 20771) +++ source/blender/makesrna/intern/rna_space.c (working copy) @@ -599,6 +599,10 @@ RNA_def_property_boolean_sdna(prop, NULL, "lock", 0); RNA_def_property_ui_text(prop, "Update Automatically", "Update other affected window spaces automatically to reflect changes during interactive operations such as transform."); + prop= RNA_def_property(srna, "display_corrected", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_CORRECTED); + RNA_def_property_ui_text(prop, "Display Corrected", "Use colour profiles to display images color/gamma corrected"); + rna_def_space_image_uv(brna); } Index: source/blender/makesrna/intern/rna_texture.c =================================================================== --- source/blender/makesrna/intern/rna_texture.c (revision 20771) +++ source/blender/makesrna/intern/rna_texture.c (working copy) @@ -272,7 +272,7 @@ prop= RNA_def_property(srna, "no_rgb", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_RGBTOINT); - RNA_def_property_ui_text(prop, "No RGB", "Converts texture RGB values to intensity (gray) values."); + RNA_def_property_ui_text(prop, "RGB to Intensity", "Converts texture RGB values to intensity (gray) values."); RNA_def_property_update(prop, NC_TEXTURE, NULL); prop= RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_VECTOR); Index: source/blender/nodes/intern/CMP_nodes/CMP_image.c =================================================================== --- source/blender/nodes/intern/CMP_nodes/CMP_image.c (revision 20771) +++ source/blender/nodes/intern/CMP_nodes/CMP_image.c (working copy) @@ -65,8 +65,11 @@ if(ibuf==NULL) return NULL; - if(ibuf->rect_float==NULL) + if(ibuf->rect_float==NULL) { + if (rd->color_mgt_flag & R_COLOR_MANAGEMENT) + ibuf->profile = IB_PROFILE_SRGB; IMB_float_from_rect(ibuf); + } type= ibuf->channels; Index: source/blender/render/intern/include/shading.h =================================================================== --- source/blender/render/intern/include/shading.h (revision 20771) +++ source/blender/render/intern/include/shading.h (working copy) @@ -49,6 +49,7 @@ ShadeResult shr[RE_MAX_OSA]; } ShadeSample; +void color_manage_linearize(float *col_to, float *col_from); /* also the node shader callback */ void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); @@ -66,6 +67,7 @@ void shade_input_set_strand_texco(struct ShadeInput *shi, struct StrandRen *strand, struct StrandVert *svert, struct StrandPoint *spoint); void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr); +void shade_input_init_material(struct ShadeInput *shi); void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample); void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl); Index: source/blender/render/intern/source/convertblender.c =================================================================== --- source/blender/render/intern/source/convertblender.c (revision 20771) +++ source/blender/render/intern/source/convertblender.c (working copy) @@ -5304,6 +5304,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob) { float mat[4][4]; + float amb[3]; unsigned int lay; int onlyselected, nolamps; @@ -5365,9 +5366,12 @@ /* still bad... doing all */ init_render_textures(re); - init_render_materials(re->r.mode, &re->wrld.ambr); + + if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) color_manage_linearize(amb, &re->wrld.ambr); + init_render_materials(re->r.mode, amb); + set_node_shader_lamp_loop(shade_material_loop); - + /* MAKE RENDER DATA */ nolamps= !ELEM3(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW); onlyselected= ELEM3(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT); Index: source/blender/render/intern/source/pipeline.c =================================================================== --- source/blender/render/intern/source/pipeline.c (revision 20771) +++ source/blender/render/intern/source/pipeline.c (working copy) @@ -2523,13 +2523,16 @@ ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.planes, 0, 0); int ok; - /* if not exists, BKE_write_ibuf makes one */ + /* if not exists, BKE_write_ibuf makes one */ ibuf->rect= (unsigned int *)rres.rect32; ibuf->rect_float= rres.rectf; ibuf->zbuf_float= rres.rectz; /* float factor for random dither, imbuf takes care of it */ ibuf->dither= scene->r.dither_intensity; + /* gamma correct to sRGB color space */ + if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) + ibuf->profile = IB_PROFILE_SRGB; ok= BKE_write_ibuf(scene, ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality); Index: source/blender/render/intern/source/pixelshading.c =================================================================== --- source/blender/render/intern/source/pixelshading.c (revision 20771) +++ source/blender/render/intern/source/pixelshading.c (working copy) @@ -58,6 +58,7 @@ #include "rendercore.h" #include "shadbuf.h" #include "pixelshading.h" +#include "shading.h" #include "sunsky.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -536,9 +537,11 @@ blend= fabs(0.5+ view[1]); } - hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; - zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb; - + if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) { + color_manage_linearize(hor, &R.wrld.horr); + color_manage_linearize(zen, &R.wrld.zenr); + } + /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */ /* SKYBLEND is active, the texture and color blend are added. */ if(R.wrld.skytype & WO_SKYTEX) { Index: source/blender/render/intern/source/rayshade.c =================================================================== --- source/blender/render/intern/source/rayshade.c (revision 20771) +++ source/blender/render/intern/source/rayshade.c (working copy) @@ -225,8 +225,7 @@ shi->obr= obi->obr; shi->vlr= vlr; shi->mat= vlr->mat; - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h - shi->har= shi->mat->har; + shade_input_init_material(shi); // Osa structs we leave unchanged now SWAP(int, osatex, shi->osatex); Index: source/blender/render/intern/source/rendercore.c =================================================================== --- source/blender/render/intern/source/rendercore.c (revision 20771) +++ source/blender/render/intern/source/rendercore.c (working copy) @@ -1515,9 +1515,7 @@ shi->mat= mat; /* init material vars */ - // note, keep this synced with render_types.h - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); - shi->har= shi->mat->har; + shade_input_init_material(shi); /* render */ shade_input_set_shade_texco(shi); @@ -1950,10 +1948,7 @@ if(shi->mat->nodetree && shi->mat->use_nodes) ntreeShaderExecTree(shi->mat->nodetree, shi, shr); else { - /* copy all relevant material vars, note, keep this synced with render_types.h */ - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); - shi->har= shi->mat->har; - + shade_input_init_material(shi); shade_material_loop(shi, shr); } } @@ -2104,9 +2099,7 @@ ShadeResult shr; VlakRen *vlr= shi->vlr; - /* init material vars */ - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h - shi->har= shi->mat->har; + shade_input_init_material(shi); if(bs->type==RE_BAKE_AO) { ambient_occlusion(shi); Index: source/blender/render/intern/source/shadeinput.c =================================================================== --- source/blender/render/intern/source/shadeinput.c (revision 20771) +++ source/blender/render/intern/source/shadeinput.c (working copy) @@ -39,6 +39,7 @@ #include "DNA_meshdata_types.h" #include "DNA_material_types.h" +#include "BKE_colortools.h" #include "BKE_utildefines.h" #include "BKE_node.h" @@ -84,11 +85,53 @@ */ +/* utility function convert an RGB triplet from sRGB to linear RGB color space */ +void color_manage_linearize(float *col_to, float *col_from) +{ + col_to[0] = srgb_to_linearrgb(col_from[0]); + col_to[1] = srgb_to_linearrgb(col_from[1]); + col_to[2] = srgb_to_linearrgb(col_from[2]); +} +/* initialise material variables in shadeinput, + * doing inverse gamma correction where applicable */ +void shade_input_init_material(ShadeInput *shi) +{ + if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) { + color_manage_linearize(&shi->r, &shi->mat->r); + color_manage_linearize(&shi->specr, &shi->mat->specr); + color_manage_linearize(&shi->mirr, &shi->mat->mirr); + + /* material ambr / ambg / ambb is overwritten from world + color_manage_linearize(shi->ambr, shi->mat->ambr); + */ + + /* note, keep this synced with render_types.h */ + memcpy(&shi->amb, &shi->mat->amb, 11*sizeof(float)); + shi->har= shi->mat->har; + } else { + /* note, keep this synced with render_types.h */ + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); + shi->har= shi->mat->har; + } + +} + +static void shadeinput_colors_linearize(ShadeInput *shi) +{ + color_manage_linearize(&shi->r, &shi->r); + color_manage_linearize(&shi->specr, &shi->specr); + color_manage_linearize(&shi->mirr, &shi->mirr); +} + /* also used as callback for nodes */ /* delivers a fully filled in ShadeResult, for all passes */ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) { + /* because node materials don't have access to rendering context, + * inverse gamma correction must happen here. evil. */ + if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT && shi->nodes == 1) + shadeinput_colors_linearize(shi); shade_lamp_loop(shi, shr); /* clears shr */ @@ -96,9 +139,7 @@ ShadeResult shr_t; float fac= shi->translucency; - /* gotta copy it again */ - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); - shi->har= shi->mat->har; + shade_input_init_material(shi); VECCOPY(shi->vn, shi->vno); VECMUL(shi->vn, -1.0f); @@ -148,8 +189,7 @@ } else { /* copy all relevant material vars, note, keep this synced with render_types.h */ - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); - shi->har= shi->mat->har; + shade_input_init_material(shi); shade_material_loop(shi, shr); } @@ -571,6 +611,13 @@ /* not supported */ } } + + if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) { + if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) { + color_manage_linearize(shi->vcol, shi->vcol); + } + } + } /* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ @@ -1240,6 +1287,12 @@ } /* else { Note! For raytracing winco is not set, important because thus means all shader input's need to have their variables set to zero else in-initialized values are used */ + if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) { + if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) { + color_manage_linearize(shi->vcol, shi->vcol); + } + } + } /* ****************** ShadeSample ************************************** */ Index: source/blender/render/intern/source/sss.c =================================================================== --- source/blender/render/intern/source/sss.c (revision 20771) +++ source/blender/render/intern/source/sss.c (working copy) @@ -55,6 +55,7 @@ #include "DNA_material_types.h" +#include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_material.h" @@ -916,7 +917,7 @@ if(!re->test_break(re->tbh)) { SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData"); float ior= mat->sss_ior, cfac= mat->sss_colfac; - float *col= mat->sss_col, *radius= mat->sss_radius; + float col[3], *radius= mat->sss_radius; float fw= mat->sss_front, bw= mat->sss_back; float error = mat->sss_error; @@ -924,6 +925,8 @@ if((re->r.scemode & R_PREVIEWBUTS) && error < 0.5f) error= 0.5f; + if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) color_manage_linearize(col, mat->sss_col); + sss->ss[0]= scatter_settings_new(col[0], radius[0], ior, cfac, fw, bw); sss->ss[1]= scatter_settings_new(col[1], radius[1], ior, cfac, fw, bw); sss->ss[2]= scatter_settings_new(col[2], radius[2], ior, cfac, fw, bw); Index: source/blender/render/intern/source/strand.c =================================================================== --- source/blender/render/intern/source/strand.c (revision 20771) +++ source/blender/render/intern/source/strand.c (working copy) @@ -281,9 +281,7 @@ shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint); /* init material vars */ - // note, keep this synced with render_types.h - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); - shi->har= shi->mat->har; + shade_input_init_material(shi); /* shade */ shade_samples_do_AO(ssamp); Index: source/blender/render/intern/source/texture.c =================================================================== --- source/blender/render/intern/source/texture.c (revision 20771) +++ source/blender/render/intern/source/texture.c (working copy) @@ -48,6 +48,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "BKE_colortools.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_plugin_types.h" @@ -1808,6 +1809,11 @@ } else texres.tin= texres.ta; + /* inverse gamma correction */ + if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) { + color_manage_linearize(tcol, tcol); + } + if(mtex->mapto & MAP_COL) { texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype); }