847 lines
27 KiB
C++
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_
|