Color:
* Accelerated sRGB <=> linear conversion using lookup table, this can speed up loading of images in the compositor and simple renders quite a bit. * Dithering now uses the Floyd-Steinberg algorithm. Previously it would simply randomize each pixel slightly, adding noise, now that should be reduced. Patch #29309 by David M.
This commit is contained in:
		| @@ -89,6 +89,8 @@ MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4]); | |||||||
| MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]); | MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]); | ||||||
| MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4]); | MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4]); | ||||||
|  |  | ||||||
|  | void BLI_init_srgb_conversion(void); | ||||||
|  |  | ||||||
| /************************** Other *************************/ | /************************** Other *************************/ | ||||||
|  |  | ||||||
| int constrain_rgb(float *r, float *g, float *b); | int constrain_rgb(float *r, float *g, float *b); | ||||||
| @@ -97,13 +99,13 @@ void minmax_rgb(short c[3]); | |||||||
| void rgb_float_set_hue_float_offset(float * rgb, float hue_offset); | void rgb_float_set_hue_float_offset(float * rgb, float hue_offset); | ||||||
| void rgb_byte_set_hue_float_offset(unsigned char * rgb, float hue_offset); | void rgb_byte_set_hue_float_offset(unsigned char * rgb, float hue_offset); | ||||||
|  |  | ||||||
|  | void rgb_byte_to_float(const unsigned char *in, float *out); | ||||||
|  | void rgb_float_to_byte(const float *in, unsigned char *out); | ||||||
|  |  | ||||||
| /***************** lift/gamma/gain / ASC-CDL conversion *****************/ | /***************** lift/gamma/gain / ASC-CDL conversion *****************/ | ||||||
|  |  | ||||||
| void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power); | void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power); | ||||||
|  |  | ||||||
| void rgb_byte_to_float(const unsigned char *in, float *out); |  | ||||||
| void rgb_float_to_byte(const float *in, unsigned char *out); |  | ||||||
|  |  | ||||||
| #ifdef BLI_MATH_INLINE_H | #ifdef BLI_MATH_INLINE_H | ||||||
| #include "intern/math_color_inline.c" | #include "intern/math_color_inline.c" | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -108,6 +108,7 @@ | |||||||
|  |  | ||||||
| #define FTOCHAR(val) ((val)<=0.0f)? 0 : (((val)>(1.0f-0.5f/255.0f))? 255 : (char)((255.0f*(val))+0.5f)) | #define FTOCHAR(val) ((val)<=0.0f)? 0 : (((val)>(1.0f-0.5f/255.0f))? 255 : (char)((255.0f*(val))+0.5f)) | ||||||
| #define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f)) | #define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f)) | ||||||
|  | #define USHORTTOUCHAR(val) ((unsigned char)(((val)+0x80)>>8)) | ||||||
| #define F3TOCHAR3(v2, v1) {                                                   \ | #define F3TOCHAR3(v2, v1) {                                                   \ | ||||||
| 		(v1)[0]= FTOCHAR((v2[0]));                                            \ | 		(v1)[0]= FTOCHAR((v2[0]));                                            \ | ||||||
| 		(v1)[1]= FTOCHAR((v2[1]));                                            \ | 		(v1)[1]= FTOCHAR((v2[1]));                                            \ | ||||||
|   | |||||||
| @@ -30,7 +30,11 @@ | |||||||
|  |  | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
|  |  | ||||||
|  | #include "MEM_guardedalloc.h" | ||||||
|  |  | ||||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||||
|  | #include "BLI_rand.h" | ||||||
|  | #include "BLI_utildefines.h" | ||||||
|  |  | ||||||
| void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) | void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) | ||||||
| { | { | ||||||
| @@ -480,3 +484,79 @@ void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset) | |||||||
| 	rgb_float_set_hue_float_offset(rgb_float, hue_offset); | 	rgb_float_set_hue_float_offset(rgb_float, hue_offset); | ||||||
| 	rgb_float_to_byte(rgb_float, rgb); | 	rgb_float_to_byte(rgb_float, rgb); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* fast sRGB conversion | ||||||
|  |  * LUT from linear float to 16-bit short | ||||||
|  |  * based on http://mysite.verizon.net/spitzak/conversion/ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | float BLI_color_from_srgb_table[256]; | ||||||
|  | unsigned short BLI_color_to_srgb_table[0x10000]; | ||||||
|  |  | ||||||
|  | static unsigned short hipart(const float f) | ||||||
|  | { | ||||||
|  | 	union { | ||||||
|  | 		float f; | ||||||
|  | 		unsigned short us[2]; | ||||||
|  | 	} tmp; | ||||||
|  |  | ||||||
|  | 	tmp.f = f; | ||||||
|  |  | ||||||
|  | #ifdef __BIG_ENDIAN__ | ||||||
|  | 	return tmp.us[0]; | ||||||
|  | #else | ||||||
|  | 	return tmp.us[1]; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static float index_to_float(const unsigned short i) | ||||||
|  | { | ||||||
|  | 	union { | ||||||
|  | 		float f; | ||||||
|  | 		unsigned short us[2]; | ||||||
|  | 	} tmp; | ||||||
|  |  | ||||||
|  | 	/* positive and negative zeros, and all gradual underflow, turn into zero: */ | ||||||
|  | 	if (i<0x80 || (i >= 0x8000 && i < 0x8080)) return 0; | ||||||
|  | 	/* All NaN's and infinity turn into the largest possible legal float: */ | ||||||
|  | 	if (i>=0x7f80 && i<0x8000) return FLT_MAX; | ||||||
|  | 	if (i>=0xff80) return -FLT_MAX; | ||||||
|  |  | ||||||
|  | #ifdef __BIG_ENDIAN__ | ||||||
|  | 	tmp.us[0] = i; | ||||||
|  | 	tmp.us[1] = 0x8000; | ||||||
|  | #else | ||||||
|  | 	tmp.us[0] = 0x8000; | ||||||
|  | 	tmp.us[1] = i; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return tmp.f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void BLI_init_srgb_conversion(void) | ||||||
|  | { | ||||||
|  | 	static int initialized= 0; | ||||||
|  | 	int i, b; | ||||||
|  |  | ||||||
|  | 	if (initialized) return; | ||||||
|  | 	initialized = 1; | ||||||
|  |  | ||||||
|  | 	/* Fill in the lookup table to convert floats to bytes: */ | ||||||
|  | 	for (i = 0; i < 0x10000; i++) { | ||||||
|  | 		float f = linearrgb_to_srgb(index_to_float(i))*255.0f; | ||||||
|  | 		if (f <= 0) BLI_color_to_srgb_table[i] = 0; | ||||||
|  | 		else if (f < 255) BLI_color_to_srgb_table[i] = (unsigned short)(f*0x100+.5); | ||||||
|  | 		else BLI_color_to_srgb_table[i] = 0xff00; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Fill in the lookup table to convert bytes to float: */ | ||||||
|  | 	for (b = 0; b <= 255; b++) { | ||||||
|  | 		float f = srgb_to_linearrgb(((float)b)*(1.0f/255.0f)); | ||||||
|  | 		BLI_color_from_srgb_table[b] = f; | ||||||
|  | 		i = hipart(f); | ||||||
|  | 		/* replace entries so byte->float->byte does not change the data: */ | ||||||
|  | 		BLI_color_to_srgb_table[i] = b*0x100; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -105,5 +105,80 @@ MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4] | |||||||
| 	srgb[3] = linear[3]; | 	srgb[3] = linear[3]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* LUT accelerated conversions */ | ||||||
|  |  | ||||||
|  | extern float BLI_color_from_srgb_table[256]; | ||||||
|  | extern unsigned short BLI_color_to_srgb_table[0x10000]; | ||||||
|  |  | ||||||
|  | MINLINE unsigned short to_srgb_table_lookup(const float f) | ||||||
|  | { | ||||||
|  | 	union { | ||||||
|  | 		float f; | ||||||
|  | 		unsigned short us[2]; | ||||||
|  | 	} tmp; | ||||||
|  | 	tmp.f = f; | ||||||
|  | #ifdef __BIG_ENDIAN__ | ||||||
|  | 	return BLI_color_to_srgb_table[tmp.us[0]]; | ||||||
|  | #else | ||||||
|  | 	return BLI_color_to_srgb_table[tmp.us[1]]; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4]) | ||||||
|  | { | ||||||
|  | 	srgb[0] = to_srgb_table_lookup(linear[0]); | ||||||
|  | 	srgb[1] = to_srgb_table_lookup(linear[1]); | ||||||
|  | 	srgb[2] = to_srgb_table_lookup(linear[2]); | ||||||
|  | 	srgb[3] = FTOUSHORT(linear[3]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE void linearrgb_to_srgb_ushort4_predivide(unsigned short srgb[4], const float linear[4]) | ||||||
|  | { | ||||||
|  | 	float alpha, inv_alpha, t; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	if(linear[3] == 1.0f || linear[3] == 0.0f) { | ||||||
|  | 		linearrgb_to_srgb_ushort4(srgb, linear); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	alpha = linear[3]; | ||||||
|  | 	inv_alpha = 1.0f/alpha; | ||||||
|  |  | ||||||
|  | 	for(i=0; i<3; ++i) { | ||||||
|  | 		t = linear[i] * inv_alpha; | ||||||
|  | 		srgb[i] = (t < 1.0f)? to_srgb_table_lookup(t) * alpha : FTOUSHORT(linearrgb_to_srgb(t) * alpha); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	srgb[3] = FTOUSHORT(linear[3]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4]) | ||||||
|  | { | ||||||
|  | 	linear[0] = BLI_color_from_srgb_table[srgb[0]]; | ||||||
|  | 	linear[1] = BLI_color_from_srgb_table[srgb[1]]; | ||||||
|  | 	linear[2] = BLI_color_from_srgb_table[srgb[2]]; | ||||||
|  | 	linear[3] = srgb[3] * (1.0f/255.0f); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4]) | ||||||
|  | { | ||||||
|  | 	float alpha, inv_alpha; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	if(srgb[3] == 255 || srgb[3] == 0) { | ||||||
|  | 		srgb_to_linearrgb_uchar4(linear, srgb); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	alpha = srgb[3] * (1.0f/255.0f); | ||||||
|  | 	inv_alpha = 1.0f/alpha; | ||||||
|  |  | ||||||
|  | 	for(i=0; i<3; ++i) | ||||||
|  | 		linear[i] = linearrgb_to_srgb(srgb[i] * inv_alpha) * alpha; | ||||||
|  |  | ||||||
|  | 	linear[3] = alpha; | ||||||
|  | } | ||||||
|  |  | ||||||
| #endif /* BLI_MATH_COLOR_INLINE_H */ | #endif /* BLI_MATH_COLOR_INLINE_H */ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -46,9 +46,9 @@ | |||||||
|  |  | ||||||
| /**************************** Interlace/Deinterlace **************************/ | /**************************** Interlace/Deinterlace **************************/ | ||||||
|  |  | ||||||
| void IMB_de_interlace(struct ImBuf *ibuf) | void IMB_de_interlace(ImBuf *ibuf) | ||||||
| { | { | ||||||
| 	struct ImBuf * tbuf1, * tbuf2; | 	ImBuf * tbuf1, * tbuf2; | ||||||
| 	 | 	 | ||||||
| 	if (ibuf == NULL) return; | 	if (ibuf == NULL) return; | ||||||
| 	if (ibuf->flags & IB_fields) return; | 	if (ibuf->flags & IB_fields) return; | ||||||
| @@ -73,9 +73,9 @@ void IMB_de_interlace(struct ImBuf *ibuf) | |||||||
| 	ibuf->y /= 2; | 	ibuf->y /= 2; | ||||||
| } | } | ||||||
|  |  | ||||||
| void IMB_interlace(struct ImBuf *ibuf) | void IMB_interlace(ImBuf *ibuf) | ||||||
| { | { | ||||||
| 	struct ImBuf * tbuf1, * tbuf2; | 	ImBuf * tbuf1, * tbuf2; | ||||||
|  |  | ||||||
| 	if (ibuf == NULL) return; | 	if (ibuf == NULL) return; | ||||||
| 	ibuf->flags &= ~IB_fields; | 	ibuf->flags &= ~IB_fields; | ||||||
| @@ -100,14 +100,76 @@ void IMB_interlace(struct ImBuf *ibuf) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /************************* Floyd-Steinberg dithering *************************/ | ||||||
|  |  | ||||||
|  | typedef struct DitherContext { | ||||||
|  | 	int *error_buf, *e; | ||||||
|  | 	int v[4], v0[4], v1[4]; | ||||||
|  | 	float f; | ||||||
|  | } DitherContext; | ||||||
|  |  | ||||||
|  | DitherContext *create_dither_context(int w, float factor) | ||||||
|  | { | ||||||
|  | 	DitherContext *di; | ||||||
|  | 	int i; | ||||||
|  | 	 | ||||||
|  | 	di= MEM_callocN(sizeof(DitherContext), "dithering context"); | ||||||
|  | 	di->f= factor / 16.0f; | ||||||
|  | 	di->error_buf= MEM_callocN(4*(w+1)*sizeof(int), "dithering error"); | ||||||
|  | 	di->e= di->error_buf; | ||||||
|  |  | ||||||
|  | 	for(i=0; i<4; ++i) | ||||||
|  | 		di->v[i]= di->v0[i]= di->v1[i]= 1024.0f*(BLI_frand()-0.5f); | ||||||
|  |  | ||||||
|  | 	return di; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void clear_dither_context(DitherContext *di) | ||||||
|  | { | ||||||
|  | 	MEM_freeN(di->error_buf); | ||||||
|  | 	MEM_freeN(di); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void dither_finish_row(DitherContext *di) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for(i=0; i<4; i++) | ||||||
|  | 		di->v[i]= di->v0[i]= di->v1[i] = 0; | ||||||
|  |  | ||||||
|  | 	di->e= di->error_buf; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE unsigned char dither_value(unsigned short v_in, DitherContext *di, int i) | ||||||
|  | { | ||||||
|  | 	int dv, d2; | ||||||
|  | 	unsigned char v_out; | ||||||
|  |  | ||||||
|  | 	di->v[i] = v_in + (2*di->v[i] + di->e[4]) * di->f; | ||||||
|  | 	CLAMP(di->v[i], 0, 0xFF00); | ||||||
|  | 	v_out = USHORTTOUCHAR(di->v[i]); | ||||||
|  | 	di->v[i] -= v_out<<8; | ||||||
|  | 	dv = di->v[i]; | ||||||
|  | 	d2 = di->v[i]<<1; | ||||||
|  | 	di->v[i] += d2; | ||||||
|  | 	*(di->e++) = di->v[i] + di->v0[i]; | ||||||
|  | 	di->v[i] += d2; | ||||||
|  |  | ||||||
|  | 	di->v0[i] = di->v[i] + di->v1[i]; | ||||||
|  | 	di->v1[i] = dv; | ||||||
|  | 	di->v[i] += d2; | ||||||
|  |  | ||||||
|  | 	return v_out; | ||||||
|  | } | ||||||
|  |  | ||||||
| /************************* Generic Buffer Conversion *************************/ | /************************* Generic Buffer Conversion *************************/ | ||||||
|  |  | ||||||
| MINLINE void byte_to_float_v4(float f[4], const uchar b[4]) | MINLINE void byte_to_float_v4(float f[4], const uchar b[4]) | ||||||
| { | { | ||||||
| 	f[0] = b[0] * (1.0f/255.0f); | 	f[0]= b[0] * (1.0f/255.0f); | ||||||
| 	f[1] = b[1] * (1.0f/255.0f); | 	f[1]= b[1] * (1.0f/255.0f); | ||||||
| 	f[2] = b[2] * (1.0f/255.0f); | 	f[2]= b[2] * (1.0f/255.0f); | ||||||
| 	f[3] = b[3] * (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]) | MINLINE void float_to_byte_v4(uchar b[4], const float f[4]) | ||||||
| @@ -115,10 +177,26 @@ MINLINE void float_to_byte_v4(uchar b[4], const float f[4]) | |||||||
| 	F4TOCHAR4(f, b); | 	F4TOCHAR4(f, b); | ||||||
| } | } | ||||||
|  |  | ||||||
| MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], float dither) | MINLINE void ushort_to_byte_v4(uchar b[4], const unsigned short us[4]) | ||||||
| { | { | ||||||
| 	float tmp[4] = {f[0]+dither, f[1]+dither, f[2]+dither, f[3]+dither}; | 	b[0]= USHORTTOUCHAR(us[0]); | ||||||
| 	float_to_byte_v4(b, tmp); | 	b[1]= USHORTTOUCHAR(us[1]); | ||||||
|  | 	b[2]= USHORTTOUCHAR(us[2]); | ||||||
|  | 	b[3]= USHORTTOUCHAR(us[3]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE void ushort_to_byte_dither_v4(uchar b[4], const unsigned short us[4], DitherContext *di) | ||||||
|  | { | ||||||
|  | 	b[0]= dither_value(us[0], di, 0); | ||||||
|  | 	b[1]= dither_value(us[0], di, 1); | ||||||
|  | 	b[2]= dither_value(us[0], di, 2); | ||||||
|  | 	b[3]= dither_value(us[0], di, 3); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di) | ||||||
|  | { | ||||||
|  | 	unsigned short us[4] = {FTOUSHORT(f[0]), FTOUSHORT(f[1]), FTOUSHORT(f[2]), FTOUSHORT(f[3])}; | ||||||
|  | 	ushort_to_byte_dither_v4(b, us, di); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* float to byte pixels, output 4-channel RGBA */ | /* float to byte pixels, output 4-channel RGBA */ | ||||||
| @@ -127,26 +205,28 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, | |||||||
| 	int width, int height, int stride_to, int stride_from) | 	int width, int height, int stride_to, int stride_from) | ||||||
| { | { | ||||||
| 	float tmp[4]; | 	float tmp[4]; | ||||||
| 	float dither_fac = dither/255.0f; |  | ||||||
| 	int x, y; | 	int x, y; | ||||||
|  | 	DitherContext *di; | ||||||
|  |  | ||||||
| 	/* we need valid profiles */ | 	/* we need valid profiles */ | ||||||
| 	BLI_assert(profile_to != IB_PROFILE_NONE); | 	BLI_assert(profile_to != IB_PROFILE_NONE); | ||||||
| 	BLI_assert(profile_from != IB_PROFILE_NONE); | 	BLI_assert(profile_from != IB_PROFILE_NONE); | ||||||
|  |  | ||||||
| 	if(channels_from==1) { | 	BLI_init_srgb_conversion(); | ||||||
| 		/* single channel input */ | 	if(dither) | ||||||
|  | 		di= create_dither_context(width, dither); | ||||||
|  |  | ||||||
| 	for(y = 0; y < height; y++) { | 	for(y = 0; y < height; y++) { | ||||||
|  | 		if(channels_from == 1) { | ||||||
|  | 		/* single channel input */ | ||||||
| 			const float *from = rect_from + stride_from*y; | 			const float *from = rect_from + stride_from*y; | ||||||
| 			uchar *to = rect_to + stride_to*y*4; | 			uchar *to = rect_to + stride_to*y*4; | ||||||
|  |  | ||||||
| 			for(x = 0; x < width; x++, from++, to+=4) | 			for(x = 0; x < width; x++, from++, to+=4) | ||||||
| 				to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]); | 				to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]); | ||||||
| 		} | 		} | ||||||
| 	} |  | ||||||
| 		else if(channels_from == 3) { | 		else if(channels_from == 3) { | ||||||
| 		/* RGB input */ | 		/* RGB input */ | ||||||
| 		for(y = 0; y < height; y++) { |  | ||||||
| 			const float *from = rect_from + stride_from*y*3; | 			const float *from = rect_from + stride_from*y*3; | ||||||
| 			uchar *to = rect_to + stride_to*y*4; | 			uchar *to = rect_to + stride_to*y*4; | ||||||
|  |  | ||||||
| @@ -174,10 +254,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} |  | ||||||
| 		else if(channels_from == 4) { | 		else if(channels_from == 4) { | ||||||
| 		/* RGBA input */ | 		/* RGBA input */ | ||||||
| 		for(y = 0; y < height; y++) { |  | ||||||
| 			const float *from = rect_from + stride_from*y*4; | 			const float *from = rect_from + stride_from*y*4; | ||||||
| 			uchar *to = rect_to + stride_to*y*4; | 			uchar *to = rect_to + stride_to*y*4; | ||||||
|  |  | ||||||
| @@ -185,7 +263,7 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, | |||||||
| 				/* no color space conversion */ | 				/* no color space conversion */ | ||||||
| 				if(dither) { | 				if(dither) { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) | 					for(x = 0; x < width; x++, from+=4, to+=4) | ||||||
| 						float_to_byte_dither_v4(to, from, (BLI_frand()-0.5f)*dither_fac); | 						float_to_byte_dither_v4(to, from, di); | ||||||
| 				} | 				} | ||||||
| 				else { | 				else { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) | 					for(x = 0; x < width; x++, from+=4, to+=4) | ||||||
| @@ -194,28 +272,30 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, | |||||||
| 			} | 			} | ||||||
| 			else if(profile_to == IB_PROFILE_SRGB) { | 			else if(profile_to == IB_PROFILE_SRGB) { | ||||||
| 				/* convert from linear to sRGB */ | 				/* convert from linear to sRGB */ | ||||||
|  | 				unsigned short us[4]; | ||||||
|  |  | ||||||
| 				if(dither && predivide) { | 				if(dither && predivide) { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) { | 					for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 						linearrgb_to_srgb_predivide_v4(tmp, from); | 						linearrgb_to_srgb_ushort4_predivide(us, from); | ||||||
| 						float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); | 						ushort_to_byte_dither_v4(to, us, di); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				else if(dither) { | 				else if(dither) { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) { | 					for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 						linearrgb_to_srgb_v4(tmp, from); | 						linearrgb_to_srgb_ushort4(us, from); | ||||||
| 						float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); | 						ushort_to_byte_dither_v4(to, us, di); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				else if(predivide) { | 				else if(predivide) { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) { | 					for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 						linearrgb_to_srgb_predivide_v4(tmp, from); | 						linearrgb_to_srgb_ushort4_predivide(us, from); | ||||||
| 						float_to_byte_v4(to, tmp); | 						ushort_to_byte_v4(to, us); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				else { | 				else { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) { | 					for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 						linearrgb_to_srgb_v4(tmp, from); | 						linearrgb_to_srgb_ushort4(us, from); | ||||||
| 						float_to_byte_v4(to, tmp); | 						ushort_to_byte_v4(to, us); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @@ -224,13 +304,13 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, | |||||||
| 				if(dither && predivide) { | 				if(dither && predivide) { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) { | 					for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 						srgb_to_linearrgb_predivide_v4(tmp, from); | 						srgb_to_linearrgb_predivide_v4(tmp, from); | ||||||
| 						float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); | 						float_to_byte_dither_v4(to, tmp, di); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				else if(dither) { | 				else if(dither) { | ||||||
| 					for(x = 0; x < width; x++, from+=4, to+=4) { | 					for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 						srgb_to_linearrgb_v4(tmp, from); | 						srgb_to_linearrgb_v4(tmp, from); | ||||||
| 						float_to_byte_dither_v4(to, tmp, (BLI_frand()-0.5f)*dither_fac); | 						float_to_byte_dither_v4(to, tmp, di); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				else if(predivide) { | 				else if(predivide) { | ||||||
| @@ -247,7 +327,13 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if(dither) | ||||||
|  | 			dither_finish_row(di); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if(dither) | ||||||
|  | 		clear_dither_context(di); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* byte to float pixels, input and output 4-channel RGBA  */ | /* byte to float pixels, input and output 4-channel RGBA  */ | ||||||
| @@ -262,6 +348,8 @@ void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from, | |||||||
| 	BLI_assert(profile_to != IB_PROFILE_NONE); | 	BLI_assert(profile_to != IB_PROFILE_NONE); | ||||||
| 	BLI_assert(profile_from != IB_PROFILE_NONE); | 	BLI_assert(profile_from != IB_PROFILE_NONE); | ||||||
|  |  | ||||||
|  | 	BLI_init_srgb_conversion(); | ||||||
|  |  | ||||||
| 	/* RGBA input */ | 	/* RGBA input */ | ||||||
| 	for(y = 0; y < height; y++) { | 	for(y = 0; y < height; y++) { | ||||||
| 		const uchar *from = rect_from + stride_from*y*4; | 		const uchar *from = rect_from + stride_from*y*4; | ||||||
| @@ -276,14 +364,12 @@ void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from, | |||||||
| 			/* convert sRGB to linear */ | 			/* convert sRGB to linear */ | ||||||
| 			if(predivide) { | 			if(predivide) { | ||||||
| 				for(x = 0; x < width; x++, from+=4, to+=4) { | 				for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 					byte_to_float_v4(tmp, from); | 					srgb_to_linearrgb_uchar4_predivide(to, from); | ||||||
| 					srgb_to_linearrgb_predivide_v4(to, tmp); |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| 				for(x = 0; x < width; x++, from+=4, to+=4) { | 				for(x = 0; x < width; x++, from+=4, to+=4) { | ||||||
| 					byte_to_float_v4(tmp, from); | 					srgb_to_linearrgb_uchar4(to, from); | ||||||
| 					srgb_to_linearrgb_v4(to, tmp); |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -451,7 +537,7 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from, | |||||||
|  |  | ||||||
| /****************************** ImBuf Conversion *****************************/ | /****************************** ImBuf Conversion *****************************/ | ||||||
|  |  | ||||||
| void IMB_rect_from_float(struct ImBuf *ibuf) | void IMB_rect_from_float(ImBuf *ibuf) | ||||||
| { | { | ||||||
| 	int predivide= (ibuf->flags & IB_cm_predivide); | 	int predivide= (ibuf->flags & IB_cm_predivide); | ||||||
| 	int profile_from; | 	int profile_from; | ||||||
| @@ -482,7 +568,7 @@ void IMB_rect_from_float(struct ImBuf *ibuf) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */ | /* 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(ImBuf *ibuf, float *buffer, int x, int y, int w, int h) | ||||||
| { | { | ||||||
| 	float *rect_float; | 	float *rect_float; | ||||||
| 	uchar *rect_byte; | 	uchar *rect_byte; | ||||||
| @@ -521,7 +607,7 @@ void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y | |||||||
| 	ibuf->userflags &= ~IB_RECT_INVALID; | 	ibuf->userflags &= ~IB_RECT_INVALID; | ||||||
| } | } | ||||||
|  |  | ||||||
| void IMB_float_from_rect(struct ImBuf *ibuf) | void IMB_float_from_rect(ImBuf *ibuf) | ||||||
| { | { | ||||||
| 	int predivide= (ibuf->flags & IB_cm_predivide); | 	int predivide= (ibuf->flags & IB_cm_predivide); | ||||||
| 	int profile_from; | 	int profile_from; | ||||||
| @@ -547,7 +633,7 @@ void IMB_float_from_rect(struct ImBuf *ibuf) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* no profile conversion */ | /* no profile conversion */ | ||||||
| void IMB_float_from_rect_simple(struct ImBuf *ibuf) | void IMB_float_from_rect_simple(ImBuf *ibuf) | ||||||
| { | { | ||||||
| 	int predivide= (ibuf->flags & IB_cm_predivide); | 	int predivide= (ibuf->flags & IB_cm_predivide); | ||||||
|  |  | ||||||
| @@ -559,7 +645,7 @@ void IMB_float_from_rect_simple(struct ImBuf *ibuf) | |||||||
| 		ibuf->x, ibuf->y, ibuf->x, ibuf->x); | 		ibuf->x, ibuf->y, ibuf->x, ibuf->x); | ||||||
| } | } | ||||||
|  |  | ||||||
| void IMB_convert_profile(struct ImBuf *ibuf, int profile) | void IMB_convert_profile(ImBuf *ibuf, int profile) | ||||||
| { | { | ||||||
| 	int predivide= (ibuf->flags & IB_cm_predivide); | 	int predivide= (ibuf->flags & IB_cm_predivide); | ||||||
| 	int profile_from, profile_to; | 	int profile_from, profile_to; | ||||||
| @@ -601,7 +687,7 @@ void IMB_convert_profile(struct ImBuf *ibuf, int profile) | |||||||
|  |  | ||||||
| /* use when you need to get a buffer with a certain profile | /* use when you need to get a buffer with a certain profile | ||||||
|  * if the return  */ |  * if the return  */ | ||||||
| float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc) | float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc) | ||||||
| { | { | ||||||
| 	int predivide= (ibuf->flags & IB_cm_predivide); | 	int predivide= (ibuf->flags & IB_cm_predivide); | ||||||
| 	int profile_from, profile_to; | 	int profile_from, profile_to; | ||||||
| @@ -649,7 +735,7 @@ float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc) | |||||||
| /**************************** Color to Grayscale *****************************/ | /**************************** Color to Grayscale *****************************/ | ||||||
|  |  | ||||||
| /* no profile conversion */ | /* no profile conversion */ | ||||||
| void IMB_color_to_bw(struct ImBuf *ibuf) | void IMB_color_to_bw(ImBuf *ibuf) | ||||||
| { | { | ||||||
| 	float *rctf= ibuf->rect_float; | 	float *rctf= ibuf->rect_float; | ||||||
| 	uchar *rct= (uchar*)ibuf->rect; | 	uchar *rct= (uchar*)ibuf->rect; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user