Files
tlib/oversampling/WDL/lice/lice_combine.h
2024-05-24 13:28:31 +02:00

847 lines
27 KiB
C++

#ifndef _LICE_COMBINE_H_
#define _LICE_COMBINE_H_
#include "../wdltypes.h"
#if defined(_MSC_VER)
#pragma warning(disable:4244) // float-to-int
#endif
#define __LICE_BOUND(x,lo,hi) ((x)<(lo)?(lo):((x)>(hi)?(hi):(x)))
#define LICE_PIXEL_HALF(x) (((x)>>1)&0x7F7F7F7F)
#define LICE_PIXEL_QUARTER(x) (((x)>>2)&0x3F3F3F3F)
#define LICE_PIXEL_EIGHTH(x) (((x)>>3)&0x1F1F1F1F)
static inline void __LICE_BilinearFilterI(int *r, int *g, int *b, int *a, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int xfrac, unsigned int yfrac)
{
const unsigned int f4=(xfrac*yfrac)>>16;
const unsigned int f3=yfrac-f4; // (1.0-xfrac)*yfrac;
const unsigned int f2=xfrac-f4; // xfrac*(1.0-yfrac);
const unsigned int f1=65536-yfrac-xfrac+f4; // (1.0-xfrac)*(1.0-yfrac);
#define DOCHAN(output, inchan) \
(output)=(pin[(inchan)]*f1 + pin[4+(inchan)]*f2 + pinnext[(inchan)]*f3 + pinnext[4+(inchan)]*f4)>>16;
DOCHAN(*r,LICE_PIXEL_R)
DOCHAN(*g,LICE_PIXEL_G)
DOCHAN(*b,LICE_PIXEL_B)
DOCHAN(*a,LICE_PIXEL_A)
#undef DOCHAN
}
static inline void __LICE_BilinearFilterIPixOut(LICE_pixel_chan *out, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int xfrac, unsigned int yfrac)
{
const unsigned int f4=(xfrac*yfrac)>>16;
const unsigned int f3=yfrac-f4; // (1.0-xfrac)*yfrac;
const unsigned int f2=xfrac-f4; // xfrac*(1.0-yfrac);
const unsigned int f1=65536-yfrac-xfrac+f4; // (1.0-xfrac)*(1.0-yfrac);
#define DOCHAN(inchan) \
(out[inchan])=(pin[(inchan)]*f1 + pin[4+(inchan)]*f2 + pinnext[(inchan)]*f3 + pinnext[4+(inchan)]*f4)>>16;
DOCHAN(LICE_PIXEL_R)
DOCHAN(LICE_PIXEL_G)
DOCHAN(LICE_PIXEL_B)
DOCHAN(LICE_PIXEL_A)
#undef DOCHAN
}
static inline void __LICE_BilinearFilterI_2(int *r, int *g, int *b, int *a, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, int npoffs, unsigned int xfrac, unsigned int yfrac)
{
const unsigned int f4=(xfrac*yfrac)>>16;
const unsigned int f3=yfrac-f4; // (1.0-xfrac)*yfrac;
const unsigned int f2=xfrac-f4; // xfrac*(1.0-yfrac);
const unsigned int f1=65536-yfrac-xfrac+f4; // (1.0-xfrac)*(1.0-yfrac);
*r=(pin[LICE_PIXEL_R]*f1 + pin[npoffs+LICE_PIXEL_R]*f2 + pinnext[LICE_PIXEL_R]*f3 + pinnext[npoffs+LICE_PIXEL_R]*f4)>>16;
*g=(pin[LICE_PIXEL_G]*f1 + pin[npoffs+LICE_PIXEL_G]*f2 + pinnext[LICE_PIXEL_G]*f3 + pinnext[npoffs+LICE_PIXEL_G]*f4)>>16;
*b=(pin[LICE_PIXEL_B]*f1 + pin[npoffs+LICE_PIXEL_B]*f2 + pinnext[LICE_PIXEL_B]*f3 + pinnext[npoffs+LICE_PIXEL_B]*f4)>>16;
*a=(pin[LICE_PIXEL_A]*f1 + pin[npoffs+LICE_PIXEL_A]*f2 + pinnext[LICE_PIXEL_A]*f3 + pinnext[npoffs+LICE_PIXEL_A]*f4)>>16;
}
static inline void __LICE_LinearFilterI(int *r, int *g, int *b, int *a, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int frac)
{
const unsigned int f=65536-frac;
*r=(pin[LICE_PIXEL_R]*f + pinnext[LICE_PIXEL_R]*frac)>>16;
*g=(pin[LICE_PIXEL_G]*f + pinnext[LICE_PIXEL_G]*frac)>>16;
*b=(pin[LICE_PIXEL_B]*f + pinnext[LICE_PIXEL_B]*frac)>>16;
*a=(pin[LICE_PIXEL_A]*f + pinnext[LICE_PIXEL_A]*frac)>>16;
}
static inline void __LICE_LinearFilterIPixOut(LICE_pixel_chan *out, const LICE_pixel_chan *pin, const LICE_pixel_chan *pinnext, unsigned int frac)
{
const unsigned int f=65536-frac;
out[LICE_PIXEL_R]=(pin[LICE_PIXEL_R]*f + pinnext[LICE_PIXEL_R]*frac)>>16;
out[LICE_PIXEL_G]=(pin[LICE_PIXEL_G]*f + pinnext[LICE_PIXEL_G]*frac)>>16;
out[LICE_PIXEL_B]=(pin[LICE_PIXEL_B]*f + pinnext[LICE_PIXEL_B]*frac)>>16;
out[LICE_PIXEL_A]=(pin[LICE_PIXEL_A]*f + pinnext[LICE_PIXEL_A]*frac)>>16;
}
static void inline _LICE_MakePixelClamp(LICE_pixel_chan *out, int r, int g, int b, int a)
{
#define LICE_PIX_MAKECHAN(a,b) out[a] = (b&~0xff) ? (b<0?0:255) : b;
LICE_PIX_MAKECHAN(LICE_PIXEL_B,b)
LICE_PIX_MAKECHAN(LICE_PIXEL_G,g)
LICE_PIX_MAKECHAN(LICE_PIXEL_R,r)
LICE_PIX_MAKECHAN(LICE_PIXEL_A,a)
#undef LICE_PIX_MAKECHAN
}
static void inline _LICE_MakePixelNoClamp(LICE_pixel_chan *out, LICE_pixel_chan r, LICE_pixel_chan g, LICE_pixel_chan b, LICE_pixel_chan a)
{
#define LICE_PIX_MAKECHAN(a,b) out[a] = b;
LICE_PIX_MAKECHAN(LICE_PIXEL_B,b)
LICE_PIX_MAKECHAN(LICE_PIXEL_G,g)
LICE_PIX_MAKECHAN(LICE_PIXEL_R,r)
LICE_PIX_MAKECHAN(LICE_PIXEL_A,a)
#undef LICE_PIX_MAKECHAN
}
#define HSV_P v*(256-s)/256
#define HSV_Q(hval) v*(16384-(hval)*s)/16384
#define HSV_T(hval) v*(16384-(64-(hval))*s)/16384
#define HSV_X v
extern unsigned short _LICE_RGB2HSV_invtab[256]; // 65536/idx - 1
#ifdef LICE_COMBINE_IMPLEMENT_HSV
LICE_pixel LICE_HSV2Pix(int h, int s, int v, int alpha)
#define __LICE_HSV2Pix LICE_HSV2Pix
#else
static inline LICE_pixel __LICE_HSV2Pix(int h, int s, int v, int alpha)
#endif
{
if (h<192)
{
if (h<64) return LICE_RGBA(HSV_X,HSV_T(h),HSV_P,alpha);
if (h<128) return LICE_RGBA(HSV_Q(h-64),HSV_X,HSV_P,alpha);
return LICE_RGBA(HSV_P,HSV_X,HSV_T(h-128),alpha);
}
if (h < 256) return LICE_RGBA(HSV_P,HSV_Q(h-192),HSV_X,alpha);
if (h < 320) return LICE_RGBA(HSV_T(h-256),HSV_P,HSV_X,alpha);
return LICE_RGBA(HSV_X,HSV_P,HSV_Q(h-320),alpha);
}
#ifdef LICE_COMBINE_IMPLEMENT_HSV
void LICE_HSV2RGB(int h, int s, int v, int* r, int* g, int* b)
#define __LICE_HSV2RGB LICE_HSV2RGB
#else
static inline void __LICE_HSV2RGB(int h, int s, int v, int* r, int* g, int* b)
#endif
{
if (h<192)
{
if (h<64)
{
*r = HSV_X; *g = HSV_T(h); *b = HSV_P;
}
else if (h<128)
{
*r = HSV_Q(h-64); *g = HSV_X; *b = HSV_P;
}
else
{
*r = HSV_P; *g = HSV_X; *b = HSV_T(h-128);
}
}
else
{
if (h < 256)
{
*r = HSV_P; *g = HSV_Q(h-192); *b = HSV_X;
}
else if (h < 320)
{
*r = HSV_T(h-256); *g = HSV_P; *b = HSV_X;
}
else
{
*r = HSV_X; *g = HSV_P; *b = HSV_Q(h-320);
}
}
}
#define LICE_RGB2HSV_USE_TABLE
// h = [0,384), s and v = [0,256)
#ifdef LICE_COMBINE_IMPLEMENT_HSV
void LICE_RGB2HSV(int r, int g, int b, int* h, int* s, int* v)
#define __LICE_RGB2HSV LICE_RGB2HSV
#else
static inline void __LICE_RGB2HSV(int r, int g, int b, int* h, int* s, int* v)
#endif
{
// this makes it just 3 conditional branches per call
int df,d,maxrgb;
int degoffs;
if (g > r)
{
if (g>b) // green max
{
maxrgb=g;
degoffs=128;
df = maxrgb - lice_min(b,r);
d=b-r;
}
else // blue max
{
maxrgb=b;
degoffs=256;
df = maxrgb - lice_min(g,r);
d=r-g;
}
}
else // r >= g
{
if (r > b) // red max
{
maxrgb=r;
if (g<b)
{
degoffs=383; // not technically correct, but close enough (and simplifies the rounding case -- if you want more accuracy, set to 384,
// then add a if (*h == 384) *h=0; after the *h assignment below
df = maxrgb - g;
}
else
{
degoffs=0;
df = maxrgb - b;
}
d=g-b;
}
else // blue max
{
maxrgb=b;
degoffs=256;
df = maxrgb - lice_min(g,r);
d=r-g;
}
}
*v = maxrgb;
#ifndef LICE_RGB2HSV_USE_TABLE // table mode doesnt need this check
if (!df) {
*h = *s = 0;
}
else
#endif
{
#ifdef LICE_RGB2HSV_USE_TABLE
*h = (d*((int)(_LICE_RGB2HSV_invtab[df]+1)))/1024 + degoffs;
*s = (df*((int)_LICE_RGB2HSV_invtab[maxrgb]))/256;
#else
*h = ((d*64)/df) + degoffs;
*s = (df*256)/(maxrgb+1);
#endif
}
}
//void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha) // alpha is ignored.
// generally speaking, the "a" is 0-255, and alpha is 0-256/1-256.
// Optimization when a=255 and alpha=1.0f, useful for doing a big vector drawn fill or something.
// This could be called _LICE_PutPixel but that would probably be confusing.
class _LICE_CombinePixelsClobberNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha) // alpha is ignored.
{
_LICE_MakePixelNoClamp(dest, r, g, b, a);
}
};
class _LICE_CombinePixelsClobberClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha) // alpha is ignored.
{
_LICE_MakePixelClamp(dest, r, g, b, a);
}
};
class _LICE_CombinePixelsClobberFAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // alpha is ignored.
{
*dest = src;
}
};
class _LICE_CombinePixelsHalfMixNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_MakePixelNoClamp(dest,
(dest[LICE_PIXEL_R]+r)>>1,
(dest[LICE_PIXEL_G]+g)>>1,
(dest[LICE_PIXEL_B]+b)>>1,
(dest[LICE_PIXEL_A]+a)>>1);
}
};
class _LICE_CombinePixelsHalfMixFAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is full range
{
*dest = ((*dest>>1) &0x7f7f7f7f) + ((src>>1)&0x7f7f7f7f);
}
};
class _LICE_CombinePixelsHalfMixClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_MakePixelClamp(dest,
(dest[LICE_PIXEL_R]+r)>>1,
(dest[LICE_PIXEL_G]+g)>>1,
(dest[LICE_PIXEL_B]+b)>>1,
(dest[LICE_PIXEL_A]+a)>>1);
}
};
class _LICE_CombinePixelsHalfMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-halfed and masked
{
*dest = ((*dest>>1) &0x7f7f7f7f) + src;
}
};
class _LICE_CombinePixelsQuarterMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-quartered and masked
{
LICE_pixel tmp = *dest;
*dest = ((tmp>>1) &0x7f7f7f7f) + ((tmp>>2) &0x3f3f3f3f) + src;
}
};
class _LICE_CombinePixelsThreeEighthMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-three-eighthed and masked
{
LICE_pixel tmp = *dest;
*dest = ((tmp>>1) &0x7f7f7f7f) + ((tmp>>3) &0x1f1f1f1f) + src;
}
};
class _LICE_CombinePixelsThreeQuarterMix2FAST
{
public:
static inline void doPixFAST(LICE_pixel *dest, LICE_pixel src) // src is pre-three-quartered and masked
{
*dest = ((*dest>>2) &0x3f3f3f3f) + src;
}
};
class _LICE_CombinePixelsCopyNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int sc=(256-alpha);
// don't check alpha=0 here, since the caller should (since alpha is usually used for static alphas)
_LICE_MakePixelNoClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
a + ((dest[LICE_PIXEL_A]-a)*sc)/256);
}
};
class _LICE_CombinePixelsCopyClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int sc=(256-alpha);
// don't check alpha=0 here, since the caller should (since alpha is usually used for static alphas)
_LICE_MakePixelClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
a + ((dest[LICE_PIXEL_A]-a)*sc)/256);
}
};
class _LICE_CombinePixelsCopySourceAlphaNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int sc2=(alpha*(a+1))/256;
const int sc = 256 - sc2;
_LICE_MakePixelNoClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
lice_min(255,sc2 + dest[LICE_PIXEL_A]));
}
}
};
class _LICE_CombinePixelsCopySourceAlphaClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int sc2=(alpha*(a+1))/256;
const int sc = 256 - sc2;
_LICE_MakePixelClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
sc2 + dest[LICE_PIXEL_A]);
}
}
};
class _LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
if (a==255)
{
_LICE_MakePixelNoClamp(dest,r,g,b,a);
}
else
{
const int sc=(255-a);
_LICE_MakePixelNoClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
lice_min(255,a + dest[LICE_PIXEL_A]));
}
}
}
};
class _LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
if (a==255)
{
_LICE_MakePixelClamp(dest,r,g,b,a);
}
else
{
const int sc=(255-a);
_LICE_MakePixelClamp(dest,
r + ((dest[LICE_PIXEL_R]-r)*sc)/256,
g + ((dest[LICE_PIXEL_G]-g)*sc)/256,
b + ((dest[LICE_PIXEL_B]-b)*sc)/256,
a + dest[LICE_PIXEL_A]);
}
}
}
};
#ifndef LICE_DISABLE_BLEND_ADD
class _LICE_CombinePixelsAdd
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// don't check alpha=0 here, since the caller should (since alpha is usually used for static alphas)
_LICE_MakePixelClamp(dest,
dest[LICE_PIXEL_R]+(r*alpha)/256,
dest[LICE_PIXEL_G]+(g*alpha)/256,
dest[LICE_PIXEL_B]+(b*alpha)/256,
dest[LICE_PIXEL_A]+(a*alpha)/256);
}
};
class _LICE_CombinePixelsAddSourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
alpha=(alpha*(a+1))/256;
_LICE_MakePixelClamp(dest,
dest[LICE_PIXEL_R]+(r*alpha)/256,
dest[LICE_PIXEL_G]+(g*alpha)/256,
dest[LICE_PIXEL_B]+(b*alpha)/256,
dest[LICE_PIXEL_A]+(a*alpha)/256);
}
}
};
#else // !LICE_DISABLE_BLEND_ADD
#define _LICE_CombinePixelsAddSourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsAdd _LICE_CombinePixelsCopyClamp
#endif
#ifndef LICE_DISABLE_BLEND_DODGE
class _LICE_CombinePixelsColorDodge
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int src_r = 256-r*alpha/256;
const int src_g = 256-g*alpha/256;
const int src_b = 256-b*alpha/256;
const int src_a = 256-a*alpha/256;
_LICE_MakePixelClamp(dest,
src_r > 1 ? 256*dest[LICE_PIXEL_R] / src_r : 256*dest[LICE_PIXEL_R],
src_g > 1 ? 256*dest[LICE_PIXEL_G] / src_g : 256*dest[LICE_PIXEL_G],
src_b > 1 ? 256*dest[LICE_PIXEL_B] / src_b : 256*dest[LICE_PIXEL_B],
src_a > 1 ? 256*dest[LICE_PIXEL_A] / src_a : 256*dest[LICE_PIXEL_A]);
}
};
class _LICE_CombinePixelsColorDodgeSourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
const int ualpha=(alpha*(a+1))/256;
const int src_r = 256-r*ualpha/256;
const int src_g = 256-g*ualpha/256;
const int src_b = 256-b*ualpha/256;
const int src_a = 256-a*ualpha/256;
_LICE_MakePixelClamp(dest,
src_r > 1 ? 256*dest[LICE_PIXEL_R] / src_r : 256*dest[LICE_PIXEL_R],
src_g > 1 ? 256*dest[LICE_PIXEL_G] / src_g : 256*dest[LICE_PIXEL_G],
src_b > 1 ? 256*dest[LICE_PIXEL_B] / src_b : 256*dest[LICE_PIXEL_B],
src_a > 1 ? 256*dest[LICE_PIXEL_A] / src_a : 256*dest[LICE_PIXEL_A]);
}
};
#else // !LICE_DISABLE_BLEND_DODGE
#define _LICE_CombinePixelsColorDodgeSourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsColorDodge _LICE_CombinePixelsCopyClamp
#endif
#ifndef LICE_DISABLE_BLEND_MUL
class _LICE_CombinePixelsMulNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// we could check alpha=0 here, but the caller should (since alpha is usually used for static alphas)
const int da=(256-alpha)*256;
_LICE_MakePixelNoClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*alpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*alpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*alpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*alpha)))>>16);
}
};
class _LICE_CombinePixelsMulClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// we could check alpha=0 here, but the caller should (since alpha is usually used for static alphas)
const int da=(256-alpha)*256;
_LICE_MakePixelClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*alpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*alpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*alpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*alpha)))>>16);
}
};
class _LICE_CombinePixelsMulSourceAlphaNoClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int ualpha=(alpha*(a+1))/256;
const int da=(256-ualpha)*256;
_LICE_MakePixelNoClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*ualpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*ualpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*ualpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*ualpha)))>>16);
}
}
};
class _LICE_CombinePixelsMulSourceAlphaClamp
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
if (a)
{
const int ualpha=(alpha*(a+1))/256;
const int da=(256-ualpha)*256;
_LICE_MakePixelClamp(dest,
(dest[LICE_PIXEL_R]*(da + (r*ualpha)))>>16,
(dest[LICE_PIXEL_G]*(da + (g*ualpha)))>>16,
(dest[LICE_PIXEL_B]*(da + (b*ualpha)))>>16,
(dest[LICE_PIXEL_A]*(da + (a*ualpha)))>>16);
}
}
};
#else // !LICE_DISABLE_BLEND_MUL
#define _LICE_CombinePixelsMulSourceAlphaNoClamp _LICE_CombinePixelsCopySourceAlphaNoClamp
#define _LICE_CombinePixelsMulSourceAlphaClamp _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsMulNoClamp _LICE_CombinePixelsCopyNoClamp
#define _LICE_CombinePixelsMulClamp _LICE_CombinePixelsCopyClamp
#endif
//#define LICE_DISABLE_BLEND_OVERLAY
#ifndef LICE_DISABLE_BLEND_OVERLAY
class _LICE_CombinePixelsOverlay
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
// we could check alpha=0 here, but the caller should (since alpha is usually used for static alphas)
int destr = dest[LICE_PIXEL_R], destg = dest[LICE_PIXEL_G], destb = dest[LICE_PIXEL_B], desta = dest[LICE_PIXEL_A];
#if 0
int srcr = r*alpha, srcg = g*alpha, srcb = b*alpha, srca = a*alpha;
int da=(256-alpha)*256;
int mr = (destr*(da+srcr))/65536;
int mg = (destg*(da+srcg))/65536;
int mb = (destb*(da+srcb))/65536;
int ma = (desta*(da+srca))/65536;
int sr = 256-(65536-srcr)*(256-destr)/65536;
int sg = 256-(65536-srcg)*(256-destg)/65536;
int sb = 256-(65536-srcb)*(256-destb)/65536;
int sa = 256-(65536-srca)*(256-desta)/65536;
destr = (destr*sr+(256-destr)*mr)/256;
destg = (destg*sg+(256-destg)*mg)/256;
destb = (destb*sb+(256-destb)*mb)/256;
desta = (desta*sa+(256-desta)*ma)/256;
#else
// can produce slightly diff (+-1) results from above due to rounding
const int da=(256-alpha)*128;
const int srcr = r*alpha+da, srcg = g*alpha+da, srcb = b*alpha+da, srca = a*alpha + da;
destr = ( destr*( (destr*(32768-srcr))/256 + srcr ) ) >> 15;
destg = ( destg*( (destg*(32768-srcg))/256 + srcg ) ) >> 15;
destb = ( destb*( (destb*(32768-srcb))/256 + srcb ) ) >> 15;
desta = ( desta*( (desta*(32768-srca))/256 + srca ) ) >> 15;
#endif
_LICE_MakePixelClamp(dest, destr, destg, destb, desta);
}
};
class _LICE_CombinePixelsOverlaySourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_CombinePixelsOverlay::doPix(dest, r, g, b, a, (alpha*(a+1))/256);
}
};
#else // !LICE_DISABLE_BLEND_OVERLAY
#define _LICE_CombinePixelsOverlaySourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsOverlay _LICE_CombinePixelsCopyClamp
#endif
//#define LICE_DISABLE_BLEND_HSVADJ
#ifndef LICE_DISABLE_BLEND_HSVADJ
class _LICE_CombinePixelsHSVAdjust
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
int h,s,v;
__LICE_RGB2HSV(dest[LICE_PIXEL_R],dest[LICE_PIXEL_G],dest[LICE_PIXEL_B],&h,&s,&v);
h+=(((r+r/2) - 192) * alpha)/256;
if (h<0)h+=384;
else if (h>=384) h-=384;
s+=((g-128)*alpha)/128;
if (s&~0xff)
{
if (s<0)s=0;
else s=255;
}
v+=((b-128)*alpha)/128;
if (v&~0xff)
{
if (v<0)v=0;
else v=255;
}
*(LICE_pixel *)dest = __LICE_HSV2Pix(h,s,v,a);
}
};
class _LICE_CombinePixelsHSVAdjustSourceAlpha
{
public:
static inline void doPix(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha)
{
_LICE_CombinePixelsHSVAdjust::doPix(dest, r, g, b, a, (alpha*(a+1))/256);
}
};
#else // !LICE_DISABLE_BLEND_HSVADJ
#define _LICE_CombinePixelsHSVAdjustSourceAlpha _LICE_CombinePixelsCopySourceAlphaClamp
#define _LICE_CombinePixelsHSVAdjust _LICE_CombinePixelsCopyClamp
#endif
// note: the "clamp" parameter would generally be false, unless you're working with
// input colors that need to be clamped (i.e. if you have a r value of >255 or <0, etc.
// if your input is LICE_pixel only then use false, and it will clamp as needed depending
// on the blend mode..
//#define __LICE__ACTION(comb) templateclass<comb>::function(parameters)
//__LICE_ACTION_SRCALPHA(mode,alpha,clamp);
//#undef __LICE__ACTION
// use this for paths that support LICE_BLIT_USE_ALPHA (source-alpha combining), but
// otherwise have constant alpha
#define __LICE_ACTION_SRCALPHA(mode,ia,clamp) \
if ((ia)!=0) switch ((mode)&(LICE_BLIT_MODE_MASK|LICE_BLIT_USE_ALPHA)) { \
case LICE_BLIT_MODE_COPY: if ((ia)>0) { \
if (clamp) { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsClobberClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsCopyClamp); } \
} else { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsClobberNoClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsCopyNoClamp); } \
} \
} \
break; \
case LICE_BLIT_MODE_ADD: __LICE__ACTION(_LICE_CombinePixelsAdd); break; \
case LICE_BLIT_MODE_DODGE: __LICE__ACTION(_LICE_CombinePixelsColorDodge); break; \
case LICE_BLIT_MODE_MUL: \
if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsMulNoClamp); } \
break; \
case LICE_BLIT_MODE_OVERLAY: __LICE__ACTION(_LICE_CombinePixelsOverlay); break; \
case LICE_BLIT_MODE_HSVADJ: __LICE__ACTION(_LICE_CombinePixelsHSVAdjust); break; \
case LICE_BLIT_MODE_COPY|LICE_BLIT_USE_ALPHA: \
if (clamp) { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmClamp);} \
else { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaClamp); } \
} else { \
if ((ia)==256) { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaIgnoreAlphaParmNoClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsCopySourceAlphaNoClamp); } \
} \
break; \
case LICE_BLIT_MODE_ADD|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsAddSourceAlpha); \
break; \
case LICE_BLIT_MODE_DODGE|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsColorDodgeSourceAlpha); \
break; \
case LICE_BLIT_MODE_MUL|LICE_BLIT_USE_ALPHA: \
if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulSourceAlphaClamp); } \
else { __LICE__ACTION(_LICE_CombinePixelsMulSourceAlphaNoClamp); } \
break; \
case LICE_BLIT_MODE_OVERLAY|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsOverlaySourceAlpha); \
break; \
case LICE_BLIT_MODE_HSVADJ|LICE_BLIT_USE_ALPHA: \
__LICE__ACTION(_LICE_CombinePixelsHSVAdjustSourceAlpha); \
break; \
}
// use this for paths that can have per pixel alpha, but calculate it themselves
#define __LICE_ACTION_NOSRCALPHA(mode, ia,clamp) \
if ((ia)!=0) switch ((mode)&LICE_BLIT_MODE_MASK) { \
case LICE_BLIT_MODE_COPY: if ((ia)>0) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsCopyClamp); } else { __LICE__ACTION(_LICE_CombinePixelsCopyNoClamp); } } break; \
case LICE_BLIT_MODE_ADD: __LICE__ACTION(_LICE_CombinePixelsAdd); break; \
case LICE_BLIT_MODE_DODGE: __LICE__ACTION(_LICE_CombinePixelsColorDodge); break; \
case LICE_BLIT_MODE_MUL: if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulClamp); } else { __LICE__ACTION(_LICE_CombinePixelsMulNoClamp); } break; \
case LICE_BLIT_MODE_OVERLAY: __LICE__ACTION(_LICE_CombinePixelsOverlay); break; \
case LICE_BLIT_MODE_HSVADJ: __LICE__ACTION(_LICE_CombinePixelsHSVAdjust); break; \
}
// For drawing where there is constant alpha and no per-pixel alpha.
#define __LICE_ACTION_CONSTANTALPHA(mode,ia,clamp) \
if ((ia)!=0) switch ((mode)&LICE_BLIT_MODE_MASK) { \
case LICE_BLIT_MODE_COPY: \
if ((ia)==256) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsClobberClamp); } else { __LICE__ACTION(_LICE_CombinePixelsClobberNoClamp); } } \
else if ((ia)==128) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsHalfMixClamp); } else { __LICE__ACTION(_LICE_CombinePixelsHalfMixNoClamp); } } \
else if ((ia)>0) { if (clamp) { __LICE__ACTION(_LICE_CombinePixelsCopyClamp); } else { __LICE__ACTION(_LICE_CombinePixelsCopyNoClamp); } } \
break; \
case LICE_BLIT_MODE_ADD: __LICE__ACTION(_LICE_CombinePixelsAdd); break; \
case LICE_BLIT_MODE_DODGE: __LICE__ACTION(_LICE_CombinePixelsColorDodge); break; \
case LICE_BLIT_MODE_MUL: if (clamp) { __LICE__ACTION(_LICE_CombinePixelsMulClamp); } else { __LICE__ACTION(_LICE_CombinePixelsMulNoClamp); } break; \
case LICE_BLIT_MODE_OVERLAY: __LICE__ACTION(_LICE_CombinePixelsOverlay); break; \
case LICE_BLIT_MODE_HSVADJ: __LICE__ACTION(_LICE_CombinePixelsHSVAdjust); break; \
}
typedef void (*LICE_COMBINEFUNC)(LICE_pixel_chan *dest, int r, int g, int b, int a, int alpha);
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(int &x, int __sc) {
const WDL_INT64 t = (((WDL_INT64) x*(__sc))/256);
x = (int) wdl_clamp(t, -WDL_INT64_CONST(0x80000000), WDL_INT64_CONST(0x7fffffff));
}
static void __LICE_SCU_INTERNAL(int &x, int __sc) {
const WDL_UINT64 t = (((WDL_UINT64) x*(__sc))>>8);
x = (unsigned int) wdl_min(t, WDL_UINT64_CONST(0xffffffff));
}
#if defined(_WIN32) || (defined(__APPLE__) && !defined(__LP64__))
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(LONG &x, int __sc) {
const WDL_INT64 t = (((WDL_INT64) x*(__sc))/256);
x = (LONG) wdl_clamp(t, -WDL_INT64_CONST(0x80000000), WDL_INT64_CONST(0x7fffffff));
}
#endif
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(float &x, int __sc) { x = (float) (((double)x * __sc) / 256.0); }
static void WDL_STATICFUNC_UNUSED __LICE_SC_INTERNAL(double &x, int __sc) { x = (x * __sc) / 256.0; }
#define __LICE_SC(x) __LICE_SC_INTERNAL(x,__sc)
#define __LICE_SCU(x) __LICE_SCU_INTERNAL(x,__sc)
#endif // _LICE_COMBINE_H_