From b9ff5840a617ec836f2d09bb0f04d60e5c3b8f67 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 28 Dec 2011 13:29:33 +0000 Subject: [PATCH 1/3] Code refactoring: add unified image buffer functions for doing float => byte, byte => float, float => float, byte => byte conversions with profile, dither and predivide. Previously code for this was spread out too much. There should be no functional changes, this is so the predivide/table/dither patches can work correctly. --- source/blender/blenkernel/BKE_colortools.h | 3 - source/blender/blenkernel/intern/colortools.c | 39 - source/blender/blenlib/BLI_math_color.h | 27 +- source/blender/blenlib/intern/math_color.c | 51 -- .../blenlib/intern/math_color_inline.c | 109 +++ .../blender/editors/render/render_internal.c | 57 +- source/blender/editors/render/render_opengl.c | 11 +- source/blender/editors/screen/glutil.c | 13 +- source/blender/imbuf/IMB_imbuf.h | 14 + source/blender/imbuf/intern/divers.c | 802 +++++++++++------- .../nodes/composite/node_composite_util.c | 11 +- .../composite/nodes/node_composite_image.c | 13 +- .../blender/render/intern/source/pipeline.c | 55 +- 13 files changed, 675 insertions(+), 530 deletions(-) create mode 100644 source/blender/blenlib/intern/math_color_inline.c diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index fd3a3fea2bb..b358209a0f4 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -45,9 +45,6 @@ struct rctf; # define DO_INLINE static inline #endif -void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w); -void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w); - struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy); void curvemapping_free(struct CurveMapping *cumap); struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap); diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 2f568aa01eb..67bd6a22348 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -52,45 +52,6 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" - -void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int UNUSED(w)) -{ - int x, y; - float *rf= rectf; - float srgb[3]; - unsigned char *rc= rectc; - - for(y=y1; y255) c[0]=255; diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c new file mode 100644 index 00000000000..aaaa065f14d --- /dev/null +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -0,0 +1,109 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: some of this file. + * + * ***** END GPL LICENSE BLOCK ***** + * */ + +/** \file blender/blenlib/intern/math_color_inline.c + * \ingroup bli + */ + + +#include "BLI_math_color.h" +#include "BLI_utildefines.h" + +#ifndef BLI_MATH_COLOR_INLINE_H +#define BLI_MATH_COLOR_INLINE_H + +/******************************** Color Space ********************************/ + +MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3]) +{ + linear[0] = srgb_to_linearrgb(srgb[0]); + linear[1] = srgb_to_linearrgb(srgb[1]); + linear[2] = srgb_to_linearrgb(srgb[2]); +} + +MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3]) +{ + srgb[0] = linearrgb_to_srgb(linear[0]); + srgb[1] = linearrgb_to_srgb(linear[1]); + srgb[2] = linearrgb_to_srgb(linear[2]); +} + +MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4]) +{ + srgb_to_linearrgb_v3_v3(linear, srgb); + linear[3] = srgb[3]; +} + +MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4]) +{ + linearrgb_to_srgb_v3_v3(srgb, linear); + srgb[3] = linear[3]; +} + +/* predivide versions to work on associated/premultipled alpha. if this should + be done or not depends on the background the image will be composited over, + ideally you would never do color space conversion on an image with alpha + because it is ill defined */ + +MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]) +{ + float alpha, inv_alpha; + + if(srgb[3] == 1.0f || srgb[3] == 0.0f) { + alpha = 1.0f; + inv_alpha = 1.0f; + } + else { + alpha = srgb[3]; + inv_alpha = 1.0f/alpha; + } + + linear[0] = srgb_to_linearrgb(srgb[0] * inv_alpha) * alpha; + linear[1] = srgb_to_linearrgb(srgb[1] * inv_alpha) * alpha; + linear[2] = srgb_to_linearrgb(srgb[2] * inv_alpha) * alpha; + linear[3] = srgb[3]; +} + +MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4]) +{ + float alpha, inv_alpha; + + if(linear[3] == 1.0f || linear[3] == 0.0f) { + alpha = 1.0f; + inv_alpha = 1.0f; + } + else { + alpha = linear[3]; + inv_alpha = 1.0f/alpha; + } + + srgb[0] = linearrgb_to_srgb(linear[0] * inv_alpha) * alpha; + srgb[1] = linearrgb_to_srgb(linear[1] * inv_alpha) * alpha; + srgb[2] = linearrgb_to_srgb(linear[2] * inv_alpha) * alpha; + srgb[3] = linear[3]; +} + +#endif /* BLI_MATH_COLOR_INLINE_H */ + diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 8a580627da3..bff93fea067 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -76,10 +76,10 @@ /* called inside thread! */ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect) { - float x1, y1, *rectf= NULL; + float *rectf= NULL; int ymin, ymax, xmin, xmax; - int rymin, rxmin, do_color_management; - char *rectc; + int rymin, rxmin, predivide, profile_from; + unsigned char *rectc; /* if renrect argument, we only refresh scanlines */ if(renrect) { @@ -136,50 +136,17 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat imb_addrectImBuf(ibuf); rectf+= 4*(rr->rectx*ymin + xmin); - rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin); + rectc= (unsigned char*)(ibuf->rect + ibuf->x*rymin + rxmin); - do_color_management = (scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)); - - /* XXX make nice consistent functions for this */ - for(y1= 0; y1dither / 255.0f; + if(scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)) + profile_from= IB_PROFILE_LINEAR_RGB; + else + profile_from= IB_PROFILE_SRGB; + predivide= 0; - /* XXX temp. because crop offset */ - if(rectc >= (char *)(ibuf->rect)) { - for(x1= 0; x1rectx; - rectc += 4*ibuf->x; - } + IMB_buffer_byte_from_float(rectc, rectf, + 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, + xmax, ymax, ibuf->x, rr->rectx); } /* ****************************** render invoking ***************** */ diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 35b21c626ed..be4d54ae2e8 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -206,14 +206,11 @@ static void screen_opengl_render_apply(OGLRender *oglrender) * float buffer. */ if(oglrender->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) { - float *rctf = rr->rectf; - int i; + int predivide= 0; /* no alpha */ - for (i = oglrender->sizex * oglrender->sizey; i > 0; i--, rctf+=4) { - rctf[0]= srgb_to_linearrgb(rctf[0]); - rctf[1]= srgb_to_linearrgb(rctf[1]); - rctf[2]= srgb_to_linearrgb(rctf[2]); - } + IMB_buffer_float_from_float(rr->rectf, rr->rectf, + 4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, predivide, + oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex); } RE_ReleaseResult(oglrender->re); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 0bba9838005..8f04940efd6 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -45,6 +45,9 @@ #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 @@ -563,17 +566,17 @@ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void * 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"); - if (do_gamma_correct) { - floatbuf_to_srgb_byte(rectf, rect32, 0, img_w, 0, img_h, img_w); - } else { - floatbuf_to_byte(rectf, rect32, 0, img_w, 0, img_h, img_w); - } + 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); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 39282335f46..7f99fc3ffc7 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -378,6 +378,20 @@ void IMB_convert_profile(struct ImBuf *ibuf, int profile); float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc); void IMB_color_to_bw(struct ImBuf *ibuf); +/* converting pixel buffers */ +void IMB_buffer_byte_from_float(unsigned char *rect_to, const float *rect_from, + int channels_from, int dither, int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from); +void IMB_buffer_float_from_byte(float *rect_to, const unsigned char *rect_from, + int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from); +void IMB_buffer_float_from_float(float *rect_to, const float *rect_from, + int channels_from, int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from); +void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect_from, + int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from); + /** * Change the ordering of the color bytes pointed to by rect from * rgba to abgr. size * 4 color bytes are reordered. diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 8c5f2dcafd6..8a3f6358c5b 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -42,10 +42,10 @@ #include "IMB_imbuf.h" #include "IMB_allocimbuf.h" -#include "BKE_colortools.h" - #include "MEM_guardedalloc.h" +/**************************** Interlace/Deinterlace **************************/ + void IMB_de_interlace(struct ImBuf *ibuf) { struct ImBuf * tbuf1, * tbuf2; @@ -100,347 +100,498 @@ void IMB_interlace(struct ImBuf *ibuf) } } +/************************* Generic Buffer Conversion *************************/ + +MINLINE void byte_to_float_v4(float f[4], const uchar b[4]) +{ + f[0] = b[0] * (1.0f/255.0f); + f[1] = b[1] * (1.0f/255.0f); + f[2] = b[2] * (1.0f/255.0f); + f[3] = b[3] * (1.0f/255.0f); +} + +MINLINE void float_to_byte_v4(uchar b[4], const float f[4]) +{ + F4TOCHAR4(f, b); +} + +MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], float dither) +{ + float tmp[4] = {f[0]+dither, f[1]+dither, f[2]+dither, f[3]+dither}; + float_to_byte_v4(b, tmp); +} + +/* float to byte pixels, output 4-channel RGBA */ +void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, + int channels_from, int dither, int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from) +{ + float tmp[4]; + float dither_fac = dither/255.0f; + int x, y; + + /* we need valid profiles */ + BLI_assert(profile_to != IB_PROFILE_NONE); + BLI_assert(profile_from != IB_PROFILE_NONE); + + if(channels_from==1) { + /* single channel input */ + for(y = 0; y < height; y++) { + const float *from = rect_from + stride_from*y; + uchar *to = rect_to + stride_to*y*4; + + for(x = 0; x < width; x++, from++, to+=4) + to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]); + } + } + else if(channels_from == 3) { + /* RGB input */ + for(y = 0; y < height; y++) { + const float *from = rect_from + stride_from*y*3; + uchar *to = rect_to + stride_to*y*4; + + if(profile_to == profile_from) { + /* no color space conversion */ + for(x = 0; x < width; x++, from+=3, to+=4) { + F3TOCHAR3(from, to); + to[3] = 255; + } + } + else if(profile_to == IB_PROFILE_SRGB) { + /* convert from linear to sRGB */ + for(x = 0; x < width; x++, from+=3, to+=4) { + linearrgb_to_srgb_v3_v3(tmp, from); + F3TOCHAR3(tmp, to); + to[3] = 255; + } + } + else if(profile_to == IB_PROFILE_LINEAR_RGB) { + /* convert from sRGB to linear */ + for(x = 0; x < width; x++, from+=3, to+=4) { + srgb_to_linearrgb_v3_v3(tmp, from); + F3TOCHAR3(tmp, to); + to[3] = 255; + } + } + } + } + else if(channels_from == 4) { + /* RGBA input */ + for(y = 0; y < height; y++) { + const float *from = rect_from + stride_from*y*4; + uchar *to = rect_to + stride_to*y*4; + + if(profile_to == profile_from) { + /* no color space conversion */ + if(dither) { + for(x = 0; x < width; x++, from+=4, to+=4) + float_to_byte_dither_v4(to, from, (BLI_frand()-0.5f)*dither_fac); + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) + float_to_byte_v4(to, from); + } + } + else if(profile_to == IB_PROFILE_SRGB) { + /* convert from linear to sRGB */ + if(dither && predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + linearrgb_to_srgb_predivide_v4(tmp, from); + float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); + } + } + else if(dither) { + for(x = 0; x < width; x++, from+=4, to+=4) { + linearrgb_to_srgb_v4(tmp, from); + float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); + } + } + else if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + linearrgb_to_srgb_predivide_v4(tmp, from); + float_to_byte_v4(to, tmp); + } + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) { + linearrgb_to_srgb_v4(tmp, from); + float_to_byte_v4(to, tmp); + } + } + } + else if(profile_to == IB_PROFILE_LINEAR_RGB) { + /* convert from sRGB to linear */ + if(dither && predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + srgb_to_linearrgb_predivide_v4(tmp, from); + float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); + } + } + else if(dither) { + for(x = 0; x < width; x++, from+=4, to+=4) { + srgb_to_linearrgb_v4(tmp, from); + float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); + } + } + else if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + srgb_to_linearrgb_predivide_v4(tmp, from); + float_to_byte_v4(to, tmp); + } + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) { + srgb_to_linearrgb_v4(tmp, from); + float_to_byte_v4(to, tmp); + } + } + } + } + } +} + +/* byte to float pixels, input and output 4-channel RGBA */ +void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from, + int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from) +{ + float tmp[4]; + int x, y; + + /* we need valid profiles */ + BLI_assert(profile_to != IB_PROFILE_NONE); + BLI_assert(profile_from != IB_PROFILE_NONE); + + /* RGBA input */ + for(y = 0; y < height; y++) { + const uchar *from = rect_from + stride_from*y*4; + float *to = rect_to + stride_to*y*4; + + if(profile_to == profile_from) { + /* no color space conversion */ + for(x = 0; x < width; x++, from+=4, to+=4) + byte_to_float_v4(to, from); + } + else if(profile_to == IB_PROFILE_LINEAR_RGB) { + /* convert sRGB to linear */ + if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + srgb_to_linearrgb_predivide_v4(to, tmp); + } + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + srgb_to_linearrgb_v4(to, tmp); + } + } + } + else if(profile_to == IB_PROFILE_SRGB) { + /* convert linear to sRGB */ + if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + linearrgb_to_srgb_predivide_v4(to, tmp); + } + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + linearrgb_to_srgb_v4(to, tmp); + } + } + } + } +} + +/* float to float pixels, output 4-channel RGBA */ +void IMB_buffer_float_from_float(float *rect_to, const float *rect_from, + int channels_from, int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from) +{ + int x, y; + + /* we need valid profiles */ + BLI_assert(profile_to != IB_PROFILE_NONE); + BLI_assert(profile_from != IB_PROFILE_NONE); + + if(channels_from==1) { + /* single channel input */ + for(y = 0; y < height; y++) { + const float *from = rect_from + stride_from*y; + float *to = rect_to + stride_to*y*4; + + for(x = 0; x < width; x++, from++, to+=4) + to[0] = to[1] = to[2] = to[3] = from[0]; + } + } + else if(channels_from == 3) { + /* RGB input */ + for(y = 0; y < height; y++) { + const float *from = rect_from + stride_from*y*3; + float *to = rect_to + stride_to*y*4; + + if(profile_to == profile_from) { + /* no color space conversion */ + for(x = 0; x < width; x++, from+=3, to+=4) { + copy_v3_v3(to, from); + to[3] = 1.0f; + } + } + else if(profile_to == IB_PROFILE_LINEAR_RGB) { + /* convert from sRGB to linear */ + for(x = 0; x < width; x++, from+=3, to+=4) { + srgb_to_linearrgb_v3_v3(to, from); + to[3] = 1.0f; + } + } + else if(profile_to == IB_PROFILE_SRGB) { + /* convert from linear to sRGB */ + for(x = 0; x < width; x++, from+=3, to+=4) { + linearrgb_to_srgb_v3_v3(to, from); + to[3] = 1.0f; + } + } + } + } + else if(channels_from == 4) { + /* RGBA input */ + for(y = 0; y < height; y++) { + const float *from = rect_from + stride_from*y*4; + float *to = rect_to + stride_to*y*4; + + if(profile_to == profile_from) { + /* same profile, copy */ + memcpy(to, from, sizeof(float)*4*width); + } + else if(profile_to == IB_PROFILE_LINEAR_RGB) { + /* convert to sRGB to linear */ + if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) + srgb_to_linearrgb_predivide_v4(to, from); + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) + srgb_to_linearrgb_v4(to, from); + } + } + else if(profile_to == IB_PROFILE_SRGB) { + /* convert from linear to sRGB */ + if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) + linearrgb_to_srgb_predivide_v4(to, from); + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) + linearrgb_to_srgb_v4(to, from); + } + } + } + } +} + +/* byte to byte pixels, input and output 4-channel RGBA */ +void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from, + int profile_to, int profile_from, int predivide, + int width, int height, int stride_to, int stride_from) +{ + float tmp[4]; + int x, y; + + /* we need valid profiles */ + BLI_assert(profile_to != IB_PROFILE_NONE); + BLI_assert(profile_from != IB_PROFILE_NONE); + + /* always RGBA input */ + for(y = 0; y < height; y++) { + const uchar *from = rect_from + stride_from*y*4; + uchar *to = rect_to + stride_to*y*4; + + if(profile_to == profile_from) { + /* same profile, copy */ + memcpy(to, from, sizeof(uchar)*4*width); + } + else if(profile_to == IB_PROFILE_LINEAR_RGB) { + /* convert to sRGB to linear */ + if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + srgb_to_linearrgb_predivide_v4(tmp, tmp); + float_to_byte_v4(to, tmp); + } + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + srgb_to_linearrgb_v4(tmp, tmp); + float_to_byte_v4(to, tmp); + } + } + } + else if(profile_to == IB_PROFILE_SRGB) { + /* convert from linear to sRGB */ + if(predivide) { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + linearrgb_to_srgb_predivide_v4(tmp, tmp); + float_to_byte_v4(to, tmp); + } + } + else { + for(x = 0; x < width; x++, from+=4, to+=4) { + byte_to_float_v4(tmp, from); + linearrgb_to_srgb_v4(tmp, tmp); + float_to_byte_v4(to, tmp); + } + } + } + } +} + +/****************************** ImBuf Conversion *****************************/ -/* assume converting from linear float to sRGB byte */ void IMB_rect_from_float(struct ImBuf *ibuf) { - /* quick method to convert floatbuf to byte */ - float *tof = (float *)ibuf->rect_float; -// int do_dither = ibuf->dither != 0.f; - float dither= ibuf->dither / 255.0f; - float srgb[4]; - int i, channels= ibuf->channels; - short profile= ibuf->profile; - unsigned char *to = (unsigned char *) ibuf->rect; - - if(tof==NULL) return; - if(to==NULL) { + int predivide= 0, profile_from; + + /* verify we have a float buffer */ + if(ibuf->rect_float==NULL) + return; + + /* create byte rect if it didn't exist yet */ + if(ibuf->rect==NULL) imb_addrectImBuf(ibuf); - to = (unsigned char *) ibuf->rect; - } - - 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]); - } - else if (profile == IB_PROFILE_LINEAR_RGB) { - if(channels == 3) { - for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) { - srgb[0]= linearrgb_to_srgb(tof[0]); - srgb[1]= linearrgb_to_srgb(tof[1]); - srgb[2]= linearrgb_to_srgb(tof[2]); - to[0] = FTOCHAR(srgb[0]); - to[1] = FTOCHAR(srgb[1]); - to[2] = FTOCHAR(srgb[2]); - to[3] = 255; - } - } - else if (channels == 4) { - if (dither != 0.f) { - for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) { - const float d = (BLI_frand()-0.5f)*dither; - - srgb[0]= d + linearrgb_to_srgb(tof[0]); - srgb[1]= d + linearrgb_to_srgb(tof[1]); - srgb[2]= d + linearrgb_to_srgb(tof[2]); - srgb[3]= d + tof[3]; - - to[0] = FTOCHAR(srgb[0]); - to[1] = FTOCHAR(srgb[1]); - to[2] = FTOCHAR(srgb[2]); - to[3] = FTOCHAR(srgb[3]); - } - } else { - floatbuf_to_srgb_byte(tof, to, 0, ibuf->x, 0, ibuf->y, ibuf->x); - } - } - } - else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { - if(channels==3) { - for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) { - to[0] = FTOCHAR(tof[0]); - to[1] = FTOCHAR(tof[1]); - to[2] = FTOCHAR(tof[2]); - to[3] = 255; - } - } - else { - if (dither != 0.f) { - for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) { - const float d = (BLI_frand()-0.5f)*dither; - float col[4]; + /* determine profiles */ + if(ibuf->profile == IB_PROFILE_LINEAR_RGB) + profile_from = IB_PROFILE_LINEAR_RGB; + else if(ELEM(ibuf->profile, IB_PROFILE_SRGB, IB_PROFILE_NONE)) + profile_from = IB_PROFILE_SRGB; + else + BLI_assert(0); - col[0]= d + tof[0]; - col[1]= d + tof[1]; - col[2]= d + tof[2]; - col[3]= d + tof[3]; + /* do conversion */ + IMB_buffer_byte_from_float((uchar*)ibuf->rect, ibuf->rect_float, + ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); - to[0] = FTOCHAR(col[0]); - to[1] = FTOCHAR(col[1]); - to[2] = FTOCHAR(col[2]); - to[3] = FTOCHAR(col[3]); - } - } else { - for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) { - to[0] = FTOCHAR(tof[0]); - to[1] = FTOCHAR(tof[1]); - to[2] = FTOCHAR(tof[2]); - to[3] = FTOCHAR(tof[3]); - } - } - } - } /* ensure user flag is reset */ ibuf->userflags &= ~IB_RECT_INVALID; } - - /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */ -void IMB_partial_rect_from_float(struct ImBuf *ibuf,float *buffer, int x, int y, int w, int h) +void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y, int w, int h) { - /* indices to source and destination image pixels */ - float *srcFloatPxl; - unsigned char *dstBytePxl; - /* buffer index will fill buffer */ - float *bufferIndex; + float *rect_float; + uchar *rect_byte; + int predivide= 0, profile_from; - /* convenience pointers to start of image buffers */ - float *init_srcFloatPxl = (float *)ibuf->rect_float; - unsigned char *init_dstBytePxl = (unsigned char *) ibuf->rect; - - /* Dithering factor */ - float dither= ibuf->dither / 255.0f; - /* respective attributes of image */ - short profile= ibuf->profile; - int channels= ibuf->channels; - - int i, j; - - /* - if called -only- from GPU_paint_update_image this test will never fail - but leaving it here for better or worse - */ - if(init_srcFloatPxl==NULL || (buffer == NULL)){ + /* verify we have a float buffer */ + if(ibuf->rect_float==NULL || buffer==NULL) return; - } - if(init_dstBytePxl==NULL) { + + /* create byte rect if it didn't exist yet */ + if(ibuf->rect==NULL) imb_addrectImBuf(ibuf); - init_dstBytePxl = (unsigned char *) ibuf->rect; - } - if(channels==1) { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x); - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl++, bufferIndex+=4) { - dstBytePxl[1]= dstBytePxl[2]= dstBytePxl[3]= dstBytePxl[0] = FTOCHAR(srcFloatPxl[0]); - bufferIndex[0] = bufferIndex[1] = bufferIndex[2] = bufferIndex[3] = srcFloatPxl[0]; - } - } - } - else if (profile == IB_PROFILE_LINEAR_RGB) { - if(channels == 3) { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3; - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex += 4) { - linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl); - F3TOCHAR4(bufferIndex, dstBytePxl); - bufferIndex[3]= 1.0; - } - } - } - else if (channels == 4) { - if (dither != 0.f) { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { - const float d = (BLI_frand()-0.5f)*dither; - linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl); - bufferIndex[3] = srcFloatPxl[3]; - add_v4_fl(bufferIndex, d); - F4TOCHAR4(bufferIndex, dstBytePxl); - } - } - } else { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { - linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl); - bufferIndex[3]= srcFloatPxl[3]; - F4TOCHAR4(bufferIndex, dstBytePxl); - } - } - } - } - } - else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { - if(channels==3) { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3; - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex+=4) { - copy_v3_v3(bufferIndex, srcFloatPxl); - F3TOCHAR4(bufferIndex, dstBytePxl); - bufferIndex[3] = 1.0; - } - } - } - else { - if (dither != 0.f) { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { - const float d = (BLI_frand()-0.5f)*dither; - copy_v4_v4(bufferIndex, srcFloatPxl); - add_v4_fl(bufferIndex,d); - F4TOCHAR4(bufferIndex, dstBytePxl); - } - } - } else { - for (j = 0; j < h; j++){ - bufferIndex = buffer + w*j*4; - dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; - srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; - for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { - copy_v4_v4(bufferIndex, srcFloatPxl); - F4TOCHAR4(bufferIndex, dstBytePxl); - } - } - } - } - } + + /* determine profiles */ + if(ibuf->profile == IB_PROFILE_LINEAR_RGB) + profile_from = IB_PROFILE_LINEAR_RGB; + else if(ELEM(ibuf->profile, IB_PROFILE_SRGB, IB_PROFILE_NONE)) + profile_from = IB_PROFILE_SRGB; + else + BLI_assert(0); + + /* do conversion */ + rect_float= ibuf->rect_float + (x + y*ibuf->x)*ibuf->channels; + rect_byte= (uchar*)ibuf->rect + (x + y*ibuf->x)*4; + + IMB_buffer_float_from_float(buffer, rect_float, + ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide, + w, h, w, ibuf->x); + + IMB_buffer_byte_from_float(rect_byte, buffer, + 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, + w, h, ibuf->x, w); + /* ensure user flag is reset */ ibuf->userflags &= ~IB_RECT_INVALID; } -static void imb_float_from_rect_nonlinear(struct ImBuf *ibuf, float *fbuf) -{ - float *tof = fbuf; - int i; - unsigned char *to = (unsigned char *) ibuf->rect; - - 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; - } -} - - -static void imb_float_from_rect_linear(struct ImBuf *ibuf, float *fbuf) -{ - float *tof = fbuf; - int i; - unsigned char *to = (unsigned char *) ibuf->rect; - - 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; - } -} - void IMB_float_from_rect(struct ImBuf *ibuf) { - /* quick method to convert byte to floatbuf */ - if(ibuf->rect==NULL) return; - if(ibuf->rect_float==NULL) { - if (imb_addrectfloatImBuf(ibuf) == 0) return; - } - - /* Float bufs should be stored linear */ + int predivide= 0, profile_from; - if (ibuf->profile != IB_PROFILE_NONE) { - /* if the image has been given a profile then we're working - * with color management in mind, so convert it to linear space */ - imb_float_from_rect_linear(ibuf, ibuf->rect_float); - } else { - imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float); - } + /* verify if we byte and float buffers */ + if(ibuf->rect==NULL) + return; + + if(ibuf->rect_float==NULL) + if(imb_addrectfloatImBuf(ibuf) == 0) + return; + + /* determine profiles */ + if(ibuf->profile == IB_PROFILE_NONE) + profile_from = IB_PROFILE_LINEAR_RGB; + else + profile_from = IB_PROFILE_SRGB; + + /* do conversion */ + IMB_buffer_float_from_byte(ibuf->rect_float, (uchar*)ibuf->rect, + IB_PROFILE_LINEAR_RGB, profile_from, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } /* no profile conversion */ void IMB_float_from_rect_simple(struct ImBuf *ibuf) { + int predivide= 0; + if(ibuf->rect_float==NULL) imb_addrectfloatImBuf(ibuf); - imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float); + + IMB_buffer_float_from_byte(ibuf->rect_float, (uchar*)ibuf->rect, + IB_PROFILE_SRGB, IB_PROFILE_SRGB, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } void IMB_convert_profile(struct ImBuf *ibuf, int profile) { - int ok= FALSE; - int i; - - unsigned char *rct= (unsigned char *)ibuf->rect; - float *rctf= ibuf->rect_float; + int predivide= 0, profile_from, profile_to; if(ibuf->profile == profile) return; - if(ELEM(ibuf->profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* from */ - if(profile == IB_PROFILE_LINEAR_RGB) { /* to */ - if(ibuf->rect_float) { - for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) { - rctf[0]= srgb_to_linearrgb(rctf[0]); - rctf[1]= srgb_to_linearrgb(rctf[1]); - rctf[2]= srgb_to_linearrgb(rctf[2]); - } - } - if(ibuf->rect) { - for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) { - rct[0]= (unsigned char)((srgb_to_linearrgb((float)rct[0]/255.0f) * 255.0f) + 0.5f); - rct[1]= (unsigned char)((srgb_to_linearrgb((float)rct[1]/255.0f) * 255.0f) + 0.5f); - rct[2]= (unsigned char)((srgb_to_linearrgb((float)rct[2]/255.0f) * 255.0f) + 0.5f); - } - } - ok= TRUE; - } - } - else if (ibuf->profile == IB_PROFILE_LINEAR_RGB) { /* from */ - if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* to */ - if(ibuf->rect_float) { - for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) { - rctf[0]= linearrgb_to_srgb(rctf[0]); - rctf[1]= linearrgb_to_srgb(rctf[1]); - rctf[2]= linearrgb_to_srgb(rctf[2]); - } - } - if(ibuf->rect) { - for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) { - rct[0]= (unsigned char)((linearrgb_to_srgb((float)rct[0]/255.0f) * 255.0f) + 0.5f); - rct[1]= (unsigned char)((linearrgb_to_srgb((float)rct[1]/255.0f) * 255.0f) + 0.5f); - rct[2]= (unsigned char)((linearrgb_to_srgb((float)rct[2]/255.0f) * 255.0f) + 0.5f); - } - } - ok= TRUE; - } + /* determine profiles */ + if(ibuf->profile == IB_PROFILE_LINEAR_RGB) + profile_from = IB_PROFILE_LINEAR_RGB; + else if(ELEM(ibuf->profile, IB_PROFILE_SRGB, IB_PROFILE_NONE)) + profile_from = IB_PROFILE_SRGB; + else + BLI_assert(0); + + if(profile == IB_PROFILE_LINEAR_RGB) + profile_to = IB_PROFILE_LINEAR_RGB; + else if(ELEM(profile, IB_PROFILE_SRGB, IB_PROFILE_NONE)) + profile_to = IB_PROFILE_SRGB; + else + BLI_assert(0); + + /* do conversion */ + if(ibuf->rect_float) { + IMB_buffer_float_from_float(ibuf->rect_float, ibuf->rect_float, + 4, profile_to, profile_from, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } - if(ok==FALSE){ - printf("IMB_convert_profile: failed profile conversion %d -> %d\n", ibuf->profile, profile); - return; + if(ibuf->rect) { + IMB_buffer_byte_from_byte((uchar*)ibuf->rect, (uchar*)ibuf->rect, + profile_to, profile_from, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } + /* set new profile */ ibuf->profile= profile; } @@ -448,18 +599,25 @@ void IMB_convert_profile(struct ImBuf *ibuf, int profile) * if the return */ float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc) { - /* stupid but it works like this everywhere now */ - const short is_lin_from= (ibuf->profile != IB_PROFILE_NONE); - const short is_lin_to= (profile != IB_PROFILE_NONE); + int predivide= 0, profile_from, profile_to; + /* determine profiles */ + if(ibuf->profile == IB_PROFILE_NONE) + profile_from = IB_PROFILE_LINEAR_RGB; + else + profile_from = IB_PROFILE_SRGB; + + if(profile == IB_PROFILE_NONE) + profile_to = IB_PROFILE_LINEAR_RGB; + else + profile_to = IB_PROFILE_SRGB; - if(is_lin_from == is_lin_to) { + if(profile_from == profile_to) { + /* simple case, just allocate the buffer and return */ *alloc= 0; - /* simple case, just allocate the buffer and return */ - if(ibuf->rect_float == NULL) { + if(ibuf->rect_float == NULL) IMB_float_from_rect(ibuf); - } return ibuf->rect_float; } @@ -469,42 +627,36 @@ float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc) *alloc= 1; if(ibuf->rect_float == NULL) { - if(is_lin_to) { - imb_float_from_rect_linear(ibuf, fbuf); - } - else { - imb_float_from_rect_nonlinear(ibuf, fbuf); - } + IMB_buffer_float_from_byte(fbuf, (uchar*)ibuf->rect, + profile_to, profile_from, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { - if(is_lin_to) { /* lin -> nonlin */ - linearrgb_to_srgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y); - } - else { /* nonlin -> lin */ - srgb_to_linearrgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y); - } + IMB_buffer_float_from_float(fbuf, ibuf->rect_float, + 4, profile_to, profile_from, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } return fbuf; } } +/**************************** Color to Grayscale *****************************/ /* no profile conversion */ void IMB_color_to_bw(struct ImBuf *ibuf) { float *rctf= ibuf->rect_float; - unsigned char *rct= (unsigned char *)ibuf->rect; + uchar *rct= (uchar*)ibuf->rect; int i; + if(rctf) { - for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) { + for(i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) rctf[0]= rctf[1]= rctf[2]= rgb_to_grayscale(rctf); - } } if(rct) { - for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) { + for(i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) rct[0]= rct[1]= rct[2]= rgb_to_grayscale_byte(rct); - } } } diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c index 99a36691b10..8aaf1771b68 100644 --- a/source/blender/nodes/composite/node_composite_util.c +++ b/source/blender/nodes/composite/node_composite_util.c @@ -606,7 +606,9 @@ void generate_preview(void *data, bNode *node, CompBuf *stackbuf) RenderData *rd= data; bNodePreview *preview= node->preview; int xsize, ysize; - int color_manage= rd->color_mgt_flag & R_COLOR_MANAGEMENT; + int profile_from= (rd->color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; + int predivide= 0; + int dither= 0; unsigned char *rect; if(preview && stackbuf) { @@ -633,10 +635,9 @@ void generate_preview(void *data, bNode *node, CompBuf *stackbuf) /* convert to byte for preview */ rect= MEM_callocN(sizeof(unsigned char)*4*xsize*ysize, "bNodePreview.rect"); - if(color_manage) - floatbuf_to_srgb_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize); - else - floatbuf_to_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize); + IMB_buffer_byte_from_float(rect, cbuf->rect, + 4, dither, IB_PROFILE_SRGB, profile_from, predivide, + xsize, ysize, xsize, xsize); free_compbuf(cbuf); if(stackbuf_use!=stackbuf) diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 9920cdab039..fd7c87adea2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -62,6 +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; *alloc= FALSE; @@ -71,7 +72,11 @@ float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc) } else { rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image"); - srgb_to_linearrgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y); + + IMB_buffer_float_from_float(rect, ibuf->rect_float, + 4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); + *alloc= TRUE; } } @@ -81,7 +86,11 @@ float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc) } else { rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image"); - linearrgb_to_srgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y); + + IMB_buffer_float_from_float(rect, ibuf->rect_float, + 4, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide, + ibuf->x, ibuf->y, ibuf->x, ibuf->x); + *alloc= TRUE; } } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index d82cff16496..0a481629ee8 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1149,32 +1149,17 @@ void RE_ResultGet32(Render *re, unsigned int *rect) RE_AcquireResultImage(re, &rres); - if(rres.rect32) + if(rres.rect32) { memcpy(rect, rres.rect32, sizeof(int)*rres.rectx*rres.recty); + } else if(rres.rectf) { - float *fp= rres.rectf; - int tot= rres.rectx*rres.recty; - char *cp= (char *)rect; - - if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) { - /* Finally convert back to sRGB rendered image */ - for(;tot>0; tot--, cp+=4, fp+=4) { - cp[0] = FTOCHAR(linearrgb_to_srgb(fp[0])); - cp[1] = FTOCHAR(linearrgb_to_srgb(fp[1])); - cp[2] = FTOCHAR(linearrgb_to_srgb(fp[2])); - cp[3] = FTOCHAR(fp[3]); - } - } - else { - /* Color management is off : no conversion necessary */ - for(;tot>0; tot--, cp+=4, fp+=4) { - cp[0] = FTOCHAR(fp[0]); - cp[1] = FTOCHAR(fp[1]); - cp[2] = FTOCHAR(fp[2]); - cp[3] = FTOCHAR(fp[3]); - } - } + int profile_from= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; + int predivide= 0; + int dither= 0; + IMB_buffer_byte_from_float((unsigned char*)rect, rres.rectf, + 4, dither, IB_PROFILE_SRGB, profile_from, predivide, + rres.rectx, rres.recty, rres.rectx, rres.rectx); } else /* else fill with black */ @@ -2567,24 +2552,18 @@ static void do_render_seq(Render * re) if(ibuf) { if(ibuf->rect_float) { + /* color management: when off ensure rectf is non-lin, since thats what the internal + * 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; + if (!rr->rectf) rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf"); - /* color management: when off ensure rectf is non-lin, since thats what the internal - * render engine delivers */ - if(re->r.color_mgt_flag & R_COLOR_MANAGEMENT) { - if(ibuf->profile == IB_PROFILE_LINEAR_RGB) - memcpy(rr->rectf, ibuf->rect_float, 4*sizeof(float)*rr->rectx*rr->recty); - else - srgb_to_linearrgb_rgba_rgba_buf(rr->rectf, ibuf->rect_float, rr->rectx*rr->recty); - - } - else { - if(ibuf->profile != IB_PROFILE_LINEAR_RGB) - memcpy(rr->rectf, ibuf->rect_float, 4*sizeof(float)*rr->rectx*rr->recty); - else - linearrgb_to_srgb_rgba_rgba_buf(rr->rectf, ibuf->rect_float, rr->rectx*rr->recty); - } + IMB_buffer_float_from_float(rr->rectf, ibuf->rect_float, + 4, profile_to, profile_from, predivide, + rr->rectx, rr->recty, rr->rectx, rr->rectx); /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 can hang around when sequence render has rendered a 32 bits one before */ From ca94cb123745f207ec837b091ab271ad3a5aacbe Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 28 Dec 2011 13:40:14 +0000 Subject: [PATCH 2/3] merge bleshes BLI_array header lib into trunk. --- source/blender/blenlib/BLI_array.h | 185 +++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 source/blender/blenlib/BLI_array.h diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h new file mode 100644 index 00000000000..bd14793e0f9 --- /dev/null +++ b/source/blender/blenlib/BLI_array.h @@ -0,0 +1,185 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* + * this library needs to be changed to not use macros quite so heavily, + * and to be more of a complete array API. The way arrays are + * exposed to client code as normal C arrays is very useful though, imho. + * it does require some use of macros, however. + * + * anyway, it's used a bit too heavily to simply rewrite as a + * more "correct" solution without macros entirely. I originally wrote this + * to be very easy to use, without the normal pain of most array libraries. + * This was especially helpful when it came to the massive refactors necessary + * for bmesh, and really helped to speed the process up. - joeedh + * + * little array macro library. example of usage: + * + * int *arr = NULL; + * BLI_array_declare(arr); + * int i; + * + * for (i=0; i<10; i++) { + * BLI_array_growone(arr); + * arr[i] = something; + * } + * BLI_array_free(arr); + * + * arrays are buffered, using double-buffering (so on each reallocation, + * the array size is doubled). supposedly this should give good Big Oh + * behaviour, though it may not be the best in practice. + */ + +#define BLI_array_declare(arr) \ + int _##arr##_count = 0; \ + void *_##arr##_tmp; \ + void *_##arr##_static = NULL + +/* this will use stack space, up to maxstatic array elements, before + * switching to dynamic heap allocation */ +#define BLI_array_staticdeclare(arr, maxstatic) \ + int _##arr##_count = 0; \ + void *_##arr##_tmp; \ + char _##arr##_static[maxstatic*sizeof(arr)] + + +/* this returns the entire size of the array, including any buffering. */ +#define BLI_array_totalsize_dyn(arr) ( \ + ((arr)==NULL) ? \ + 0 : \ + MEM_allocN_len(arr) / sizeof(*arr) \ +) + + +#define BLI_array_totalsize(arr) ( \ + (size_t) \ + (((void *)(arr) == (void *)_##arr##_static && (void *)(arr) != NULL) ? \ + (sizeof(_##arr##_static) / sizeof(*arr)) : \ + BLI_array_totalsize_dyn(arr)) \ +) + + +/* this returns the logical size of the array, not including buffering. */ +#define BLI_array_count(arr) _##arr##_count + +/* Grow the array by a fixed number of items. zeroes the new elements. + * + * Allow for a large 'num' value when the new size is more then double + * to allocate the exact sized array. */ +#define _bli_array_grow_items(arr, num) ( \ + (BLI_array_totalsize(arr) >= _##arr##_count + num) ? \ + (_##arr##_count += num) : \ + ( \ + (void) (_##arr##_tmp = MEM_callocN( \ + sizeof(*arr) * (num < _##arr##_count ? \ + (_##arr##_count * 2 + 2) : \ + (_##arr##_count + num)), \ + #arr " " __FILE__ ":" STRINGIFY(__LINE__) \ + ) \ + ), \ + (void) (arr && memcpy(_##arr##_tmp, \ + arr, \ + sizeof(*arr) * _##arr##_count) \ + ), \ + (void) (arr && ((void *)(arr) != (void*)_##arr##_static ? \ + (MEM_freeN(arr), arr) : \ + arr) \ + ), \ + (void) (arr = _##arr##_tmp \ + ), \ + (_##arr##_count += num) \ + ) \ +) + +/* grow an array by a specified number of items */ +#define BLI_array_growitems(arr, num) ( \ + ((void *)(arr)==NULL && (void *)(_##arr##_static) != NULL) ? \ + ((arr= (void*)_##arr##_static), (_##arr##_count += num)) : \ + _bli_array_grow_items(arr, num) \ +) + +/* returns length of array */ +#define BLI_array_growone(arr) BLI_array_growitems(arr, 1) + + +/* appends an item to the array. */ +#define BLI_array_append(arr, item) ( \ + (void) BLI_array_growone(arr), \ + (void) (arr[_##arr##_count - 1] = item) \ +) + +/* appends an item to the array and returns a pointer to the item in the array. + * item is not a pointer, but actual data value.*/ +#define BLI_array_append_r(arr, item) ( \ + (void) BLI_array_growone(arr), \ + (void) (arr[_##arr##_count - 1] = item), \ + (&arr[_##arr##_count - 1]) \ +) + +#define BLI_array_free(arr) \ + if (arr && (char *)arr != _##arr##_static) { \ + BLI_array_fake_user(arr); \ + MEM_freeN(arr); \ + } + +#define BLI_array_pop(arr) ( \ + (arr&&_##arr##_count) ? \ + arr[--_##arr##_count] : \ + 0 \ +) + +/* resets the logical size of an array to zero, but doesn't + * free the memory. */ +#define BLI_array_empty(arr) \ + _##arr##_count=0 + +/* set the count of the array, doesn't actually increase the allocated array + * size. don't use this unless you know what you're doing. */ +#define BLI_array_set_length(arr, count) \ + _##arr##_count = (count) + +/* only to prevent unused warnings */ +#define BLI_array_fake_user(arr) \ + (void)_##arr##_count, \ + (void)_##arr##_tmp, \ + (void)_##arr##_static + + +/* not part of the 'API' but handy funcs, + * same purpose as BLI_array_staticdeclare() + * but use when the max size is known ahead of time */ +#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \ + char _##arr##_static[maxstatic*sizeof(*arr)]; \ + const int _##arr##_is_static= ((void *)_##arr##_static) != ( \ + arr= (realsize <= maxstatic) ? \ + (void *)_##arr##_static : \ + MEM_mallocN(sizeof(*arr)*realsize, allocstr) \ + ) \ + +#define BLI_array_fixedstack_free(arr) \ + if (_##arr##_is_static) MEM_freeN(arr) \ + From 5b88e16306711408825d9291bfeb7023bd7fd69c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 28 Dec 2011 13:50:33 +0000 Subject: [PATCH 3/3] WIP loading bmesh in trunk, some conversion functions for this purpose. --- source/blender/blenkernel/intern/mesh.c | 175 +++++++++++++++++- source/blender/blenlib/CMakeLists.txt | 1 + source/blender/blenloader/intern/writefile.c | 4 +- source/blender/makesdna/DNA_mesh_types.h | 2 +- source/blender/python/intern/bpy_app_ffmpeg.c | 6 +- .../windowmanager/intern/wm_operators.c | 4 +- 6 files changed, 185 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 4b4875213b1..61604bf1432 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -65,6 +65,10 @@ /* -- */ #include "BKE_object.h" +#ifdef USE_BMESH_FORWARD_COMPAT +#include "BLI_array.h" +#endif + EditMesh *BKE_mesh_get_editmesh(Mesh *me) { @@ -726,7 +730,7 @@ void mball_to_mesh(ListBase *lb, Mesh *me) nors= dl->nors; verts= dl->verts; while(a--) { - VECCOPY(mvert->co, verts); + copy_v3_v3(mvert->co, verts); normal_float_to_short_v3(mvert->no, nors); mvert++; nors+= 3; @@ -1445,6 +1449,175 @@ void create_vert_edge_map(ListBase **map, IndexNode **mem, const MEdge *medge, c } } +#ifdef USE_BMESH_FORWARD_COMPAT + +void mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata, + CustomData *pdata, int lindex[4], int findex, + const int polyindex, + const int mf_len /* 3 or 4 */ + ) +{ + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL); + int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + for(i=0; i < numTex; i++){ + texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); + texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i); + + texface->tpage = texpoly->tpage; + texface->flag = texpoly->flag; + texface->transp = texpoly->transp; + texface->mode = texpoly->mode; + texface->tile = texpoly->tile; + texface->unwrap = texpoly->unwrap; + + for (j=0; j < mf_len; j++) { + mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i); + texface->uv[j][0] = mloopuv->uv[0]; + texface->uv[j][1] = mloopuv->uv[1]; + } + } + + for(i=0; i < numCol; i++){ + mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); + + for (j=0; j < mf_len; j++) { + mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + } + } + + if (hasWCol) { + mcol = CustomData_get(fdata, findex, CD_WEIGHT_MCOL); + + for (j=0; j < mf_len; j++) { + mloopcol = CustomData_get(ldata, lindex[j], CD_WEIGHT_MLOOPCOL); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + } + } +} + + +/* + * this function recreates a tesselation. + * returns number of tesselation faces. + */ +int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, + struct CustomData *pdata, int totface, int UNUSED(totloop), int totpoly) +{ + MLoop *mloop; + + int lindex[4]; + int i; + int k; + + MPoly *mp, *mpoly; + MFace *mface = NULL, *mf; + BLI_array_declare(mface); + + mpoly = CustomData_get_layer(pdata, CD_MPOLY); + mloop = CustomData_get_layer(ldata, CD_MLOOP); + + mp = mpoly; + k = 0; + for (i = 0; itotloop, 3, 4)) { + BLI_array_growone(mface); + mf = &mface[k]; + + mf->mat_nr = mp->mat_nr; + mf->flag = mp->flag; + + mf->v1 = mp->loopstart + 0; + mf->v2 = mp->loopstart + 1; + mf->v3 = mp->loopstart + 2; + mf->v4 = (mp->totloop == 4) ? (mp->loopstart + 3) : 0; + + /* abuse edcode for temp storage and clear next loop */ + mf->edcode = (char)mp->totloop; /* only ever 3 or 4 */ + + k++; + } + } + + CustomData_free(fdata, totface); + memset(fdata, 0, sizeof(CustomData)); + + totface= k; + + CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); + + CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + + mp = mpoly; + k = 0; + for (i = 0; itotloop, 3, 4)) { + mf = &mface[k]; + + if (mf->edcode == 3) { + /*sort loop indices to ensure winding is correct*/ + /* NO SORT - looks like we can skip this */ + + lindex[0] = mf->v1; + lindex[1] = mf->v2; + lindex[2] = mf->v3; + lindex[3] = 0; /* unused */ + + /*transform loop indices to vert indices*/ + mf->v1 = mloop[mf->v1].v; + mf->v2 = mloop[mf->v2].v; + mf->v3 = mloop[mf->v3].v; + + mesh_loops_to_mface_corners(fdata, ldata, pdata, + lindex, k, i, 3); + test_index_face(mf, fdata, totface, 3); + } + else { + /*sort loop indices to ensure winding is correct*/ + /* NO SORT - looks like we can skip this */ + + lindex[0] = mf->v1; + lindex[1] = mf->v2; + lindex[2] = mf->v3; + lindex[3] = mf->v4; + + /*transform loop indices to vert indices*/ + mf->v1 = mloop[mf->v1].v; + mf->v2 = mloop[mf->v2].v; + mf->v3 = mloop[mf->v3].v; + mf->v4 = mloop[mf->v4].v; + + mesh_loops_to_mface_corners(fdata, ldata, pdata, + lindex, k, i, 4); + test_index_face(mf, fdata, totface, 4); + } + + mf->edcode= 0; + + k++; + } + } + + return k; +} + +#endif /* USE_BMESH_FORWARD_COMPAT */ + + + /* basic vertex data functions */ int minmax_mesh(Mesh *me, float min[3], float max[3]) { diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index fb9b8021b8e..a03aee7cb7c 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -87,6 +87,7 @@ set(SRC intern/voxel.c intern/winstuff.c + BLI_array.h BLI_args.h BLI_blenlib.h BLI_boxpack2d.h diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index f4575c3b1e3..e9c14404057 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -175,7 +175,7 @@ typedef struct { int tot, count, error, memsize; -#ifdef USE_MESH_FORWARDS_COMAT +#ifdef USE_BMESH_SAVE_AS_COMPAT char use_mesh_compat; /* option to save with older mesh format */ #endif } WriteData; @@ -2625,7 +2625,7 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil wd= bgnwrite(handle, compare, current); -#ifdef USE_MESH_FORWARDS_COMAT +#ifdef USE_BMESH_SAVE_AS_COMPAT wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0; #endif diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 8e8c3b8743a..ca471bbabcd 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -198,7 +198,7 @@ typedef struct TFace { * will eventually be removed */ #if 0 /* enable in bmesh branch only for now */ -#define USE_MESH_FORWARDS_COMAT +#define USE_BMESH_SAVE_AS_COMPAT #endif diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c index 9c4428919ec..778334c9600 100644 --- a/source/blender/python/intern/bpy_app_ffmpeg.c +++ b/source/blender/python/intern/bpy_app_ffmpeg.c @@ -69,7 +69,11 @@ static PyStructSequence_Desc app_ffmpeg_info_desc = { static PyObject *make_ffmpeg_info(void) { PyObject *ffmpeg_info; - int pos = 0, curversion; + int pos = 0; + +#ifdef WITH_FFMPEG + int curversion; +#endif ffmpeg_info = PyStructSequence_New(&BlenderAppFFmpegType); if (ffmpeg_info == NULL) { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index db8f9794c88..29d2f9392b2 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -46,7 +46,7 @@ #include "DNA_scene_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" -#include "DNA_mesh_types.h" /* only for USE_MESH_FORWARDS_COMAT */ +#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */ #include "BLF_translation.h" @@ -2012,7 +2012,7 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot) RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file"); RNA_def_boolean(ot->srna, "relative_remap", 1, "Remap Relative", "Remap relative paths when saving in a different directory"); RNA_def_boolean(ot->srna, "copy", 0, "Save Copy", "Save a copy of the actual working state but does not make saved file active"); -#ifdef USE_MESH_FORWARDS_COMAT +#ifdef USE_BMESH_SAVE_AS_COMPAT RNA_def_boolean(ot->srna, "use_mesh_compat", 0, "Legacy Mesh Format", "Save using legacy mesh format (no ngons)"); #endif }