forked from bartvdbraak/blender
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:
parent
3dead22c73
commit
4487103e61
@ -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();
|
||||||
|
if(dither)
|
||||||
|
di= create_dither_context(width, dither);
|
||||||
|
|
||||||
|
for(y = 0; y < height; y++) {
|
||||||
|
if(channels_from == 1) {
|
||||||
/* single channel input */
|
/* single channel input */
|
||||||
for(y = 0; y < height; y++) {
|
|
||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user