3059 lines
83 KiB
C++
3059 lines
83 KiB
C++
/*
|
|
Cockos WDL - LICE - Lightweight Image Compositing Engine
|
|
Copyright (C) 2007 and later, Cockos Incorporated
|
|
File: lice.cpp (LICE core processing)
|
|
See lice.h for license and other information
|
|
*/
|
|
|
|
|
|
#ifndef __LICE_CPP_IMPLEMENTED__
|
|
#define __LICE_CPP_IMPLEMENTED__
|
|
|
|
#ifndef WDL_NO_DEFINE_MINMAX
|
|
#define WDL_NO_DEFINE_MINMAX
|
|
#endif
|
|
#include "lice.h"
|
|
#include <math.h>
|
|
#include <stdio.h> // only included in case we need to debug with sprintf etc
|
|
|
|
#include "lice_combine.h"
|
|
#include "lice_extended.h"
|
|
|
|
#ifndef _WIN32
|
|
#include "../swell/swell.h"
|
|
#endif
|
|
|
|
#define IGNORE_SCALING(mode) ((mode)&LICE_BLIT_IGNORE_SCALING)
|
|
|
|
#define DO_RECT_SC(mode) \
|
|
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL); \
|
|
if (__sc>0) { \
|
|
if (!IGNORE_SCALING(mode)) { \
|
|
__LICE_SC(x); \
|
|
__LICE_SC(y); \
|
|
__LICE_SCU(w); \
|
|
__LICE_SCU(h); \
|
|
} \
|
|
__LICE_SCU(destbm_w); \
|
|
__LICE_SCU(destbm_h); \
|
|
}
|
|
|
|
|
|
|
|
_LICE_ImageLoader_rec *LICE_ImageLoader_list;
|
|
|
|
LICE_pixel LICE_CombinePixels(LICE_pixel dest, LICE_pixel src, float alpha, int mode)
|
|
{
|
|
int r = LICE_GETR(src);
|
|
int g = LICE_GETG(src);
|
|
int b = LICE_GETB(src);
|
|
int a = LICE_GETA(src);
|
|
int al = (int)(alpha*256.0f);
|
|
|
|
#define __LICE__ACTION(COMBFUNC) COMBFUNC::doPix((LICE_pixel_chan*)&dest,r, g, b, a, al)
|
|
__LICE_ACTION_SRCALPHA(mode, al,false);
|
|
#undef __LICE__ACTION
|
|
|
|
return dest;
|
|
}
|
|
|
|
|
|
void LICE_CombinePixels2(LICE_pixel *destptr, int r, int g, int b, int a, int ia, int mode)
|
|
{
|
|
#define __LICE__ACTION(COMBFUNC) COMBFUNC::doPix((LICE_pixel_chan*)destptr,r, g, b, a, ia)
|
|
__LICE_ACTION_SRCALPHA(mode, ia, false);
|
|
#undef __LICE__ACTION
|
|
}
|
|
void LICE_CombinePixels2Clamp(LICE_pixel *destptr, int r, int g, int b, int a, int ia, int mode)
|
|
{
|
|
#define __LICE__ACTION(COMBFUNC) COMBFUNC::doPix((LICE_pixel_chan*)destptr,r, g, b, a, ia)
|
|
__LICE_ACTION_SRCALPHA(mode, ia, true);
|
|
#undef __LICE__ACTION
|
|
}
|
|
|
|
|
|
LICE_MemBitmap::LICE_MemBitmap(int w, int h, unsigned int linealign)
|
|
{
|
|
m_allocsize=0;
|
|
m_fb=0;
|
|
m_width=0;
|
|
m_height=0;
|
|
m_linealign = linealign > 1 ? ((linealign & ~(linealign-1))-1) : 0; // force to be contiguous bits
|
|
if (m_linealign>16) m_linealign=16;
|
|
if (w>0&&h>0) __resize(w,h);
|
|
}
|
|
|
|
LICE_MemBitmap::~LICE_MemBitmap() { free(m_fb); }
|
|
|
|
bool LICE_MemBitmap::__resize(int w, int h)
|
|
{
|
|
if (w!=m_width||h!=m_height)
|
|
{
|
|
#ifdef DEBUG_TIGHT_ALLOC // dont enable for anything you want to be even remotely fast
|
|
free(m_fb);
|
|
m_fb = (LICE_pixel *)malloc((m_allocsize = ((w+m_linealign)&~m_linealign)*h*sizeof(LICE_pixel)) + LICE_MEMBITMAP_ALIGNAMT);
|
|
m_width=m_fb?w:0;
|
|
m_height=m_fb?h:0;
|
|
return true;
|
|
#endif
|
|
int sz=(((m_width=w)+m_linealign)&~m_linealign)*(m_height=h)*sizeof(LICE_pixel);
|
|
|
|
if (sz<=0||w<1||h<1) { free(m_fb); m_fb=0; m_allocsize=0; }
|
|
else if (!m_fb) m_fb=(LICE_pixel*)malloc((m_allocsize=sz) + LICE_MEMBITMAP_ALIGNAMT);
|
|
else
|
|
{
|
|
if (sz>m_allocsize)
|
|
{
|
|
void *op=m_fb;
|
|
if (!(m_fb=(LICE_pixel*)realloc(m_fb,(m_allocsize=sz+sz/4)+LICE_MEMBITMAP_ALIGNAMT)))
|
|
{
|
|
free(op);
|
|
m_fb=(LICE_pixel*)malloc((m_allocsize=sz)+LICE_MEMBITMAP_ALIGNAMT);
|
|
}
|
|
}
|
|
}
|
|
if (!m_fb) {m_width=m_height=0; }
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
#ifndef _LICE_NO_SYSBITMAPS_
|
|
|
|
LICE_SysBitmap::LICE_SysBitmap(int w, int h)
|
|
{
|
|
m_allocw=m_alloch=0;
|
|
#ifdef _WIN32
|
|
m_dc = CreateCompatibleDC(NULL);
|
|
m_bitmap = 0;
|
|
m_oldbitmap = 0;
|
|
#else
|
|
m_dc=0;
|
|
#endif
|
|
m_bits=0;
|
|
m_width=m_height=0;
|
|
m_adv_scaling=0;
|
|
m_draw_scaling=0;
|
|
|
|
__resize(w,h);
|
|
}
|
|
|
|
|
|
LICE_SysBitmap::~LICE_SysBitmap()
|
|
{
|
|
#ifdef _WIN32
|
|
if (m_oldbitmap && m_dc) SelectObject(m_dc,m_oldbitmap);
|
|
if (m_bitmap) DeleteObject(m_bitmap);
|
|
if (m_dc) DeleteDC(m_dc);
|
|
#else
|
|
if (m_dc)
|
|
SWELL_DeleteGfxContext(m_dc);
|
|
#endif
|
|
}
|
|
|
|
bool LICE_SysBitmap::__resize(int w, int h)
|
|
{
|
|
#ifdef _WIN32
|
|
if (!m_dc) { m_width=m_height=0; m_bits=0; return false; }
|
|
#endif
|
|
|
|
if (m_width==w && m_height == h) return false;
|
|
|
|
m_width=w;
|
|
m_height=h;
|
|
|
|
if (m_draw_scaling > 0)
|
|
{
|
|
w = (w * m_draw_scaling) >> 8;
|
|
h = (h * m_draw_scaling) >> 8;
|
|
}
|
|
w = (w+3)&~3; // always keep backing store a multiple of 4px wide
|
|
|
|
#ifndef DEBUG_TIGHT_ALLOC
|
|
// dont resize down bitmaps
|
|
if (w && h && w <= m_allocw && h <= m_alloch && m_bits)
|
|
{
|
|
#ifndef _WIN32
|
|
if (isFlipped())
|
|
{
|
|
m_bits=(LICE_pixel*)SWELL_GetCtxFrameBuffer(m_dc);
|
|
m_bits += (m_alloch-h)*m_allocw;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
#endif//!DEBUG_TIGHT_ALLOC
|
|
|
|
m_allocw=w;
|
|
m_alloch=h;
|
|
|
|
#ifdef _WIN32
|
|
if (m_oldbitmap)
|
|
{
|
|
SelectObject(m_dc,m_oldbitmap);
|
|
m_oldbitmap=0;
|
|
}
|
|
if (m_bitmap) DeleteObject(m_bitmap);
|
|
m_bitmap=0;
|
|
m_bits=0;
|
|
|
|
|
|
if (w<1 || h<1) return false;
|
|
|
|
BITMAPINFO pbmInfo = {0,};
|
|
pbmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmInfo.bmiHeader.biWidth = w;
|
|
pbmInfo.bmiHeader.biHeight = isFlipped()?h:-h;
|
|
pbmInfo.bmiHeader.biPlanes = 1;
|
|
pbmInfo.bmiHeader.biBitCount = sizeof(LICE_pixel)*8;
|
|
pbmInfo.bmiHeader.biCompression = BI_RGB;
|
|
m_bitmap = CreateDIBSection( NULL, &pbmInfo, DIB_RGB_COLORS, (void **)&m_bits, NULL, 0);
|
|
|
|
if (m_bitmap) m_oldbitmap=SelectObject(m_dc, m_bitmap);
|
|
else { m_width=m_height=0; m_bits=0; }
|
|
#else
|
|
if (m_dc) SWELL_DeleteGfxContext(m_dc);
|
|
m_dc=0;
|
|
m_bits=0;
|
|
|
|
if (w<1 || h<1) return false;
|
|
|
|
m_dc=SWELL_CreateMemContext(0,w,h);
|
|
if (!m_dc) { m_width=m_height=0; m_bits=0; }
|
|
else m_bits=(LICE_pixel*)SWELL_GetCtxFrameBuffer(m_dc);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // _LICE_NO_SYSBITMAPS_
|
|
|
|
|
|
|
|
#ifndef LICE_NO_BLIT_SUPPORT
|
|
void LICE_Copy(LICE_IBitmap *dest, LICE_IBitmap *src) // resizes dest
|
|
{
|
|
if (src&&dest)
|
|
{
|
|
dest->resize(src->getWidth(),src->getHeight());
|
|
LICE_Blit(dest,src,0,0,NULL,1.0,LICE_BLIT_MODE_COPY);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template<class COMBFUNC> class _LICE_Template_Blit0 // these always templated
|
|
{
|
|
public:
|
|
static void solidBlitFAST(LICE_pixel *dest, int w, int h,
|
|
LICE_pixel color,
|
|
int dest_span)
|
|
{
|
|
while (h--)
|
|
{
|
|
LICE_pixel *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
COMBFUNC::doPixFAST(pout,color);
|
|
++pout;
|
|
}
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void scaleBlitFAST(LICE_pixel_chan *dest, const LICE_pixel_chan *src, int w, int h,
|
|
int icurx, int icury, int idx, int idy, unsigned int clipright, unsigned int clipbottom,
|
|
int src_span, int dest_span)
|
|
{
|
|
LICE_pixel* destpx = (LICE_pixel*) dest;
|
|
int destpxspan = dest_span*(int)sizeof(LICE_pixel_chan)/(int)sizeof(LICE_pixel);
|
|
|
|
while (h--)
|
|
{
|
|
const unsigned int cury = icury >> 16;
|
|
if (cury < clipbottom)
|
|
{
|
|
int curx=icurx;
|
|
const LICE_pixel_chan *inptr=src + cury * src_span;
|
|
LICE_pixel* pout = destpx;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const unsigned int offs=curx >> 16;
|
|
if (offs<clipright)
|
|
{
|
|
COMBFUNC::doPixFAST(pout,((LICE_pixel *)inptr)[offs]);
|
|
}
|
|
|
|
++pout;
|
|
curx+=idx;
|
|
}
|
|
}
|
|
destpx += destpxspan;
|
|
icury+=idy;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
#ifndef LICE_FAVOR_SIZE_EXTREME
|
|
template<class COMBFUNC>
|
|
#endif
|
|
class _LICE_Template_Blit1 // these controlled by LICE_FAVOR_SIZE_EXTREME
|
|
{
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
#define DOPIX(pout,r,g,b,a,ia) combFunc(pout,r,g,b,a,ia);
|
|
#else
|
|
#define DOPIX(pout,r,g,b,a,ia) COMBFUNC::doPix(pout,r,g,b,a,ia);
|
|
#endif
|
|
public:
|
|
static void solidBlit(LICE_pixel_chan *dest, int w, int h,
|
|
int ir, int ig, int ib, int pxa, int ia,
|
|
int dest_span
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
)
|
|
{
|
|
while (h--)
|
|
{
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
DOPIX(pout,ir,ig,ib,pxa,ia);
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
}
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
static void gradBlit(LICE_pixel_chan *dest, int w, int h,
|
|
int ir, int ig, int ib, int ia,
|
|
int drdx, int dgdx, int dbdx, int dadx,
|
|
int drdy, int dgdy, int dbdy, int dady,
|
|
int dest_span
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
)
|
|
{
|
|
while (h--)
|
|
{
|
|
int r=ir,g=ig,b=ib,a=ia;
|
|
ir+=drdy; ig+=dgdy; ib+=dbdy; ia+=dady;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const int aa=a/65536;
|
|
DOPIX(pout,r/65536,g/65536,b/65536,aa,aa);
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
r+=drdx; g+=dgdx; b+=dbdx; a+=dadx;
|
|
}
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
|
|
#undef DOPIX
|
|
};
|
|
|
|
|
|
#ifndef LICE_FAVOR_SIZE
|
|
template<class COMBFUNC>
|
|
#endif
|
|
class _LICE_Template_Blit2 // these controlled by LICE_FAVOR_SIZE
|
|
{
|
|
#ifdef LICE_FAVOR_SIZE
|
|
#define DOPIX(pout,r,g,b,a,ia) combFunc(pout,r,g,b,a,ia);
|
|
#else
|
|
#define DOPIX(pout,r,g,b,a,ia) COMBFUNC::doPix(pout,r,g,b,a,ia);
|
|
#endif
|
|
|
|
public:
|
|
|
|
static void blit(LICE_pixel_chan *dest, const LICE_pixel_chan *src, int w, int h, int src_span, int dest_span, int ia
|
|
#ifdef LICE_FAVOR_SIZE
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
)
|
|
{
|
|
while (h-->0)
|
|
{
|
|
int n=w;
|
|
const LICE_pixel_chan *pin=src;
|
|
LICE_pixel_chan *pout=dest;
|
|
while (n--)
|
|
{
|
|
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],ia);
|
|
|
|
pin += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
}
|
|
dest+=dest_span;
|
|
src += src_span;
|
|
}
|
|
}
|
|
|
|
// this is only designed for filtering down an image approx 2:1 to 4:1 or so.. it'll work (poortly) for higher, and for less it's crap too.
|
|
// probably need to redo it using linear interpolation of the filter coefficients, but bleh I'm gonna go play some call of duty
|
|
static void scaleBlitFilterDown(LICE_pixel_chan *dest, const LICE_pixel_chan *src, int w, int h,
|
|
int icurx, int icury, int idx, int idy, int clipright, int clipbottom,
|
|
int src_span, int dest_span, int ia, const int *filter, int filt_start, int filtsz
|
|
#ifdef LICE_FAVOR_SIZE
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
|
|
)
|
|
{
|
|
|
|
while (h--)
|
|
{
|
|
int cury = icury >> 16;
|
|
int curx=icurx;
|
|
int n=w;
|
|
if (cury >= 0 && cury < clipbottom)
|
|
{
|
|
const LICE_pixel_chan *inptr=src + (cury+filt_start) * src_span;
|
|
LICE_pixel_chan *pout=dest;
|
|
while (n--)
|
|
{
|
|
int offs=curx >> 16;
|
|
if (offs>=0 && offs<clipright)
|
|
{
|
|
int r=0,g=0,b=0,a=0;
|
|
int sc=0;
|
|
int fy=filtsz;
|
|
int ypos=cury+filt_start;
|
|
const LICE_pixel_chan *rdptr = inptr + (offs + filt_start)*(int) (sizeof(LICE_pixel)/sizeof(LICE_pixel_chan));
|
|
const int *scaletab = filter;
|
|
while (fy--)
|
|
{
|
|
if (ypos >= clipbottom) break;
|
|
|
|
if (ypos >= 0)
|
|
{
|
|
int xpos=offs + filt_start;
|
|
const LICE_pixel_chan *pin = rdptr;
|
|
int fx=filtsz;
|
|
while (fx--)
|
|
{
|
|
int tsc = *scaletab++;
|
|
if (xpos >= 0 && xpos < clipright)
|
|
{
|
|
r+=pin[LICE_PIXEL_R]*tsc;
|
|
g+=pin[LICE_PIXEL_G]*tsc;
|
|
b+=pin[LICE_PIXEL_B]*tsc;
|
|
a+=pin[LICE_PIXEL_A]*tsc;
|
|
sc+=tsc;
|
|
}
|
|
xpos++;
|
|
pin+=sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
}
|
|
}
|
|
else scaletab += filtsz;
|
|
|
|
ypos++;
|
|
rdptr+=src_span;
|
|
}
|
|
if (sc>0)
|
|
{
|
|
DOPIX(pout,r/sc,g/sc,b/sc,a/sc,ia);
|
|
}
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
curx+=idx;
|
|
}
|
|
}
|
|
dest+=dest_span;
|
|
icury+=idy;
|
|
}
|
|
}
|
|
static void scaleBlit(LICE_pixel_chan *dest, const LICE_pixel_chan *src, int w, int h,
|
|
int icurx, int icury, int idx, int idy, unsigned int clipright, unsigned int clipbottom,
|
|
int src_span, int dest_span, int ia, int filtermode
|
|
#ifdef LICE_FAVOR_SIZE
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
|
|
)
|
|
{
|
|
|
|
if (filtermode == LICE_BLIT_FILTER_BILINEAR)
|
|
{
|
|
while (h--)
|
|
{
|
|
const unsigned int cury = icury >> 16;
|
|
const int yfrac=icury&65535;
|
|
int curx=icurx;
|
|
const LICE_pixel_chan *inptr=src + cury * src_span;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
if (cury < clipbottom-1)
|
|
{
|
|
while (n--)
|
|
{
|
|
const unsigned int offs=curx >> 16;
|
|
const LICE_pixel_chan *pin = inptr + offs*sizeof(LICE_pixel);
|
|
if (offs<clipright-1)
|
|
{
|
|
int r,g,b,a;
|
|
__LICE_BilinearFilterI(&r,&g,&b,&a,pin,pin+src_span,curx&0xffff,yfrac);
|
|
DOPIX(pout,r,g,b,a,ia)
|
|
}
|
|
else if (offs==clipright-1)
|
|
{
|
|
int r,g,b,a;
|
|
__LICE_LinearFilterI(&r,&g,&b,&a,pin,pin+src_span,yfrac);
|
|
DOPIX(pout,r,g,b,a,ia)
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
curx+=idx;
|
|
}
|
|
}
|
|
else if (cury == clipbottom-1)
|
|
{
|
|
while (n--)
|
|
{
|
|
const unsigned int offs=curx >> 16;
|
|
const LICE_pixel_chan *pin = inptr + offs*sizeof(LICE_pixel);
|
|
if (offs<clipright-1)
|
|
{
|
|
int r,g,b,a;
|
|
__LICE_LinearFilterI(&r,&g,&b,&a,pin,pin+sizeof(LICE_pixel)/sizeof(LICE_pixel_chan),curx&0xffff);
|
|
DOPIX(pout,r,g,b,a,ia)
|
|
}
|
|
else if (offs==clipright-1)
|
|
{
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],ia)
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
curx+=idx;
|
|
}
|
|
}
|
|
dest+=dest_span;
|
|
icury+=idy;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (h--)
|
|
{
|
|
const unsigned int cury = icury >> 16;
|
|
if (cury < clipbottom)
|
|
{
|
|
int curx=icurx;
|
|
const LICE_pixel_chan *inptr=src + cury * src_span;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const unsigned int offs=curx >> 16;
|
|
if (offs<clipright)
|
|
{
|
|
const LICE_pixel_chan *pin = inptr + offs*sizeof(LICE_pixel);
|
|
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],ia)
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
curx+=idx;
|
|
}
|
|
}
|
|
dest+=dest_span;
|
|
icury+=idy;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#undef DOPIX
|
|
};
|
|
|
|
#ifdef LICE_FAVOR_SPEED
|
|
template<class COMBFUNC>
|
|
#endif
|
|
class _LICE_Template_Blit3 // stuff controlled by LICE_FAVOR_SPEED
|
|
{
|
|
#ifndef LICE_FAVOR_SPEED
|
|
#define DOPIX(pout,r,g,b,a,ia) combFunc(pout,r,g,b,a,ia);
|
|
#else
|
|
#define DOPIX(pout,r,g,b,a,ia) COMBFUNC::doPix(pout,r,g,b,a,ia);
|
|
#endif
|
|
|
|
public:
|
|
|
|
static void deltaBlit(LICE_pixel_chan *dest, const LICE_pixel_chan *src, int w, int h,
|
|
int isrcx, int isrcy, int idsdx, int idtdx, int idsdy, int idtdy,
|
|
int idsdxdy, int idtdxdy,
|
|
unsigned int src_right, unsigned int src_bottom,
|
|
int src_span, int dest_span, int ia, int filtermode
|
|
#ifndef LICE_FAVOR_SPEED
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
)
|
|
{
|
|
if (filtermode == LICE_BLIT_FILTER_BILINEAR)
|
|
{
|
|
while (h--)
|
|
{
|
|
int thisx=isrcx;
|
|
int thisy=isrcy;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const unsigned int cury = thisy >> 16;
|
|
const unsigned int curx = thisx >> 16;
|
|
if (cury < src_bottom-1)
|
|
{
|
|
if (curx < src_right-1)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
int r,g,b,a;
|
|
|
|
__LICE_BilinearFilterI(&r,&g,&b,&a,pin,pin+src_span,thisx&65535,thisy&65535);
|
|
|
|
DOPIX(pout,r,g,b,a,ia);
|
|
}
|
|
else if (curx==src_right-1)
|
|
{
|
|
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
int r,g,b,a;
|
|
|
|
__LICE_LinearFilterI(&r,&g,&b,&a,pin,pin+src_span,thisy&65535);
|
|
DOPIX(pout,r,g,b,a,ia);
|
|
}
|
|
}
|
|
else if (cury==src_bottom-1)
|
|
{
|
|
if (curx<src_right-1)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
|
|
int r,g,b,a;
|
|
|
|
__LICE_LinearFilterI(&r,&g,&b,&a,pin,pin+sizeof(LICE_pixel)/sizeof(LICE_pixel_chan),thisx&65535);
|
|
|
|
DOPIX(pout,r,g,b,a,ia);
|
|
}
|
|
else if (curx==src_right-1)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],ia);
|
|
}
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
thisx+=idsdx;
|
|
thisy+=idtdx;
|
|
}
|
|
idsdx+=idsdxdy;
|
|
idtdx+=idtdxdy;
|
|
isrcx+=idsdy;
|
|
isrcy+=idtdy;
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (h--)
|
|
{
|
|
int thisx=isrcx;
|
|
int thisy=isrcy;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const unsigned int cury = thisy >> 16;
|
|
const unsigned int curx = thisx >> 16;
|
|
if (cury < src_bottom && curx < src_right)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],ia);
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
thisx+=idsdx;
|
|
thisy+=idtdx;
|
|
}
|
|
idsdx+=idsdxdy;
|
|
idtdx+=idtdxdy;
|
|
isrcx+=idsdy;
|
|
isrcy+=idtdy;
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef DOPIX
|
|
};
|
|
|
|
#ifdef LICE_FAVOR_SPEED
|
|
template<class COMBFUNC>
|
|
#endif
|
|
class _LICE_Template_Blit4 // stuff controlled by LICE_FAVOR_SPEED
|
|
{
|
|
#ifndef LICE_FAVOR_SPEED
|
|
#define DOPIX(pout,r,g,b,a,ia) combFunc(pout,r,g,b,a,ia);
|
|
#else
|
|
#define DOPIX(pout,r,g,b,a,ia) COMBFUNC::doPix(pout,r,g,b,a,ia);
|
|
#endif
|
|
|
|
public:
|
|
|
|
static void deltaBlitAlpha(LICE_pixel_chan *dest, const LICE_pixel_chan *src, int w, int h,
|
|
int isrcx, int isrcy, int idsdx, int idtdx, int idsdy, int idtdy,
|
|
int idsdxdy, int idtdxdy,
|
|
unsigned int src_right, unsigned int src_bottom,
|
|
int src_span, int dest_span, int ia, int idadx, int idady, int idadxdy, int filtermode
|
|
#ifndef LICE_FAVOR_SPEED
|
|
, LICE_COMBINEFUNC combFunc
|
|
#endif
|
|
)
|
|
{
|
|
if (filtermode == LICE_BLIT_FILTER_BILINEAR)
|
|
{
|
|
while (h--)
|
|
{
|
|
int thisx=isrcx;
|
|
int thisy=isrcy;
|
|
int thisa=ia;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const unsigned int cury = thisy >> 16;
|
|
const unsigned int curx = thisx >> 16;
|
|
if (cury < src_bottom-1)
|
|
{
|
|
if (curx < src_right-1)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
int r,g,b,a;
|
|
|
|
__LICE_BilinearFilterI(&r,&g,&b,&a,pin,pin+src_span,thisx&65535,thisy&65535);
|
|
|
|
DOPIX(pout,r,g,b,a,thisa>>8);
|
|
}
|
|
else if (curx==src_right-1)
|
|
{
|
|
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
int r,g,b,a;
|
|
|
|
__LICE_LinearFilterI(&r,&g,&b,&a,pin,pin+src_span,thisy&65535);
|
|
DOPIX(pout,r,g,b,a,thisa>>8);
|
|
}
|
|
}
|
|
else if (cury==src_bottom-1)
|
|
{
|
|
if (curx<src_right-1)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
|
|
int r,g,b,a;
|
|
|
|
__LICE_LinearFilterI(&r,&g,&b,&a,pin,pin+sizeof(LICE_pixel)/sizeof(LICE_pixel_chan),thisx&65535);
|
|
|
|
DOPIX(pout,r,g,b,a,thisa>>8);
|
|
}
|
|
else if (curx==src_right-1)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],thisa>>8);
|
|
}
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
thisx+=idsdx;
|
|
thisy+=idtdx;
|
|
thisa+=idadx;
|
|
}
|
|
idsdx+=idsdxdy;
|
|
idtdx+=idtdxdy;
|
|
idadx+=idadxdy;
|
|
isrcx+=idsdy;
|
|
isrcy+=idtdy;
|
|
ia += idady;
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (h--)
|
|
{
|
|
int thisx=isrcx;
|
|
int thisy=isrcy;
|
|
int thisa=ia;
|
|
LICE_pixel_chan *pout=dest;
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
const unsigned int cury = thisy >> 16;
|
|
const unsigned int curx = thisx >> 16;
|
|
if (cury < src_bottom && curx < src_right)
|
|
{
|
|
const LICE_pixel_chan *pin = src + cury * src_span + curx*sizeof(LICE_pixel);
|
|
|
|
DOPIX(pout,pin[LICE_PIXEL_R],pin[LICE_PIXEL_G],pin[LICE_PIXEL_B],pin[LICE_PIXEL_A],thisa>>8);
|
|
}
|
|
|
|
pout += sizeof(LICE_pixel)/sizeof(LICE_pixel_chan);
|
|
thisx+=idsdx;
|
|
thisy+=idtdx;
|
|
thisa+=idadx;
|
|
}
|
|
idsdx+=idsdxdy;
|
|
idtdx+=idtdxdy;
|
|
idadx+=idadxdy;
|
|
isrcx+=idsdy;
|
|
isrcy+=idtdy;
|
|
ia+=idady;
|
|
dest+=dest_span;
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef DOPIX
|
|
};
|
|
|
|
|
|
|
|
#ifndef LICE_NO_GRADIENT_SUPPORT
|
|
|
|
void LICE_GradRect(LICE_IBitmap *dest, int dstx, int dsty, int dstw, int dsth,
|
|
float ir, float ig, float ib, float ia,
|
|
float drdx, float dgdx, float dbdx, float dadx,
|
|
float drdy, float dgdy, float dbdy, float dady,
|
|
int mode)
|
|
{
|
|
if (!dest) return;
|
|
|
|
ir*=255.0; ig*=255.0; ib*=255.0; ia*=256.0;
|
|
drdx*=255.0; dgdx*=255.0; dbdx*=255.0; dadx*=256.0;
|
|
drdy*=255.0; dgdy*=255.0; dbdy*=255.0; dady*=256.0;
|
|
// dont scale alpha
|
|
|
|
// clip to output
|
|
if (dstx < 0)
|
|
{
|
|
ir-=dstx*drdx; ig-=dstx*dgdx; ib-=dstx*dbdx; ia-=dstx*dadx;
|
|
dstw+=dstx;
|
|
dstx=0;
|
|
}
|
|
if (dsty < 0)
|
|
{
|
|
ir -= dsty*drdy; ig-=dsty*dgdy; ib -= dsty*dbdy; ia -= dsty*dady;
|
|
dsth += dsty;
|
|
dsty=0;
|
|
}
|
|
|
|
int dest_span=dest->getRowSpan()*sizeof(LICE_pixel);
|
|
LICE_pixel_chan *pdest = (LICE_pixel_chan *)dest->getBits();
|
|
|
|
const int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
|
|
if (!pdest || !dest_span || dstw < 1 || dsth < 1 || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (dstw > destbm_w-dstx) dstw = destbm_w-dstx;
|
|
if (dsth > destbm_h-dsty) dsth = destbm_h-dsty;
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else
|
|
{
|
|
pdest += dsty*dest_span;
|
|
}
|
|
pdest+=dstx*sizeof(LICE_pixel);
|
|
#define TOFIX(a) ((int)((a)*65536.0))
|
|
|
|
int iir=TOFIX(ir), iig=TOFIX(ig), iib=TOFIX(ib), iia=TOFIX(ia), idrdx=TOFIX(drdx),idgdx=TOFIX(dgdx),idbdx=TOFIX(dbdx),idadx=TOFIX(dadx),
|
|
idrdy=TOFIX(drdy), idgdy=TOFIX(dgdy), idbdy=TOFIX(dbdy), idady=TOFIX(dady);
|
|
|
|
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc=comb::doPix;
|
|
#else
|
|
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit1<comb>::gradBlit(pdest,dstw,dsth,iir,iig,iib,iia,idrdx,idgdx,idbdx,idadx,idrdy,idgdy,idbdy,idady,dest_span)
|
|
#endif
|
|
|
|
// todo: could predict whether or not the colors will ever go out of 0.255 range and optimize
|
|
|
|
if ((mode & LICE_BLIT_MODE_MASK)==LICE_BLIT_MODE_COPY && iia==65536 && idady==0 && idadx == 0)
|
|
{
|
|
__LICE__ACTION(_LICE_CombinePixelsClobberClamp);
|
|
}
|
|
else
|
|
{
|
|
__LICE_ACTION_NOSRCALPHA(mode,256,true);
|
|
}
|
|
#undef __LICE__ACTION
|
|
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
if (blitfunc) _LICE_Template_Blit1::gradBlit(pdest,dstw,dsth,iir,iig,iib,iia,idrdx,idgdx,idbdx,idadx,idrdy,idgdy,idbdy,idady,dest_span,blitfunc);
|
|
#endif
|
|
|
|
#undef TOFIX
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifndef LICE_NO_BLIT_SUPPORT
|
|
|
|
static void LICE_BlitInt(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, const RECT *srcrect, float alpha, int mode, bool allowSc)
|
|
{
|
|
if (!dest || !src || !alpha) return;
|
|
|
|
int srcbm_w = src->getWidth(), srcbm_h = src->getHeight();
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
int __sc2 = (int)src->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc2 > 0)
|
|
{
|
|
const int __sc = __sc2;
|
|
__LICE_SCU(srcbm_w);
|
|
__LICE_SCU(srcbm_h);
|
|
}
|
|
|
|
RECT sr={0,0,srcbm_w, srcbm_h};
|
|
if (srcrect)
|
|
{
|
|
sr=*srcrect;
|
|
if (sr.left < 0) { dstx-=sr.left; sr.left=0; }
|
|
if (sr.top < 0) { dsty-=sr.top; sr.top=0; }
|
|
if (sr.right > srcbm_w) sr.right=srcbm_w;
|
|
if (sr.bottom > srcbm_h) sr.bottom=srcbm_h;
|
|
}
|
|
|
|
int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (allowSc && __sc != __sc2 && !IGNORE_SCALING(mode))
|
|
{
|
|
const int w = sr.right-sr.left, h=sr.bottom-sr.top;
|
|
LICE_ScaledBlit(dest,src,dstx,dsty,w,h, sr.left,sr.top,w,h,alpha,mode);
|
|
return;
|
|
}
|
|
if (__sc>0)
|
|
{
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(dstx);
|
|
__LICE_SC(dsty);
|
|
}
|
|
}
|
|
if (__sc2>0 && !IGNORE_SCALING(mode))
|
|
{
|
|
__sc=__sc2;
|
|
__LICE_SC(sr.left);
|
|
__LICE_SC(sr.right);
|
|
__LICE_SC(sr.top);
|
|
__LICE_SC(sr.bottom);
|
|
}
|
|
|
|
|
|
// clip to output
|
|
if (dstx < 0) { sr.left -= dstx; dstx=0; }
|
|
if (dsty < 0) { sr.top -= dsty; dsty=0; }
|
|
|
|
if (sr.left < 0 || sr.top < 0) return; // overflow check
|
|
if (sr.right <= sr.left || sr.bottom <= sr.top || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (sr.right > sr.left + (destbm_w-dstx)) sr.right = sr.left + (destbm_w-dstx);
|
|
if (sr.bottom > sr.top + (destbm_h-dsty)) sr.bottom = sr.top + (destbm_h-dsty);
|
|
|
|
// ignore blits that are 0
|
|
if (sr.right <= sr.left || sr.bottom <= sr.top) return;
|
|
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_BLIT_ACCEL))
|
|
{
|
|
LICE_Ext_Blit_acceldata data(src, dstx, dsty,
|
|
sr.left, sr.top,
|
|
sr.right-sr.left, sr.bottom-sr.top,
|
|
alpha, mode);
|
|
if (dest->Extended(LICE_EXT_BLIT_ACCEL, &data)) return;
|
|
}
|
|
#endif
|
|
|
|
|
|
int dest_span=dest->getRowSpan()*sizeof(LICE_pixel);
|
|
int src_span=src->getRowSpan()*sizeof(LICE_pixel);
|
|
const LICE_pixel_chan *psrc = (LICE_pixel_chan *)src->getBits();
|
|
LICE_pixel_chan *pdest = (LICE_pixel_chan *)dest->getBits();
|
|
if (!psrc || !pdest) return;
|
|
|
|
if (src->isFlipped())
|
|
{
|
|
psrc += (src->getHeight()-sr.top - 1)*src_span;
|
|
src_span=-src_span;
|
|
}
|
|
else psrc += sr.top*src_span;
|
|
psrc += sr.left*sizeof(LICE_pixel);
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else pdest += dsty*dest_span;
|
|
pdest+=dstx*sizeof(LICE_pixel);
|
|
|
|
int i=sr.bottom-sr.top;
|
|
int cpsize=sr.right-sr.left;
|
|
|
|
if ((mode&LICE_BLIT_MODE_MASK) >= LICE_BLIT_MODE_CHANCOPY && (mode&LICE_BLIT_MODE_MASK) < LICE_BLIT_MODE_CHANCOPY+0x10)
|
|
{
|
|
while (i-->0)
|
|
{
|
|
LICE_pixel_chan *o=pdest+((mode>>2)&3);
|
|
const LICE_pixel_chan *in=psrc+(mode&3);
|
|
int a=cpsize;
|
|
while (a--)
|
|
{
|
|
*o=*in;
|
|
o+=sizeof(LICE_pixel);
|
|
in+=sizeof(LICE_pixel);
|
|
}
|
|
pdest+=dest_span;
|
|
psrc += src_span;
|
|
}
|
|
}
|
|
// special fast case for copy with no source alpha and alpha=1.0 or 0.5
|
|
else if ((mode&(LICE_BLIT_MODE_MASK|LICE_BLIT_USE_ALPHA))==LICE_BLIT_MODE_COPY && (alpha==1.0||alpha==0.5))
|
|
{
|
|
if (alpha==0.5)
|
|
{
|
|
while (i-->0)
|
|
{
|
|
int a=cpsize;
|
|
const LICE_pixel *rd = (LICE_pixel *)psrc;
|
|
LICE_pixel *wr = (LICE_pixel *)pdest;
|
|
while (a-->0)
|
|
{
|
|
*wr = ((*wr>>1)&0x7f7f7f7f)+((*rd++>>1)&0x7f7f7f7f);
|
|
wr++;
|
|
}
|
|
|
|
pdest+=dest_span;
|
|
psrc += src_span;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (i-->0)
|
|
{
|
|
memmove(pdest,psrc,cpsize*sizeof(LICE_pixel));
|
|
pdest+=dest_span;
|
|
psrc += src_span;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int ia=(int)(alpha*256.0);
|
|
#ifdef LICE_FAVOR_SIZE
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc=comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit2<comb>::blit(pdest,psrc,cpsize,i,src_span,dest_span,ia)
|
|
#endif
|
|
|
|
__LICE_ACTION_SRCALPHA(mode,ia,false);
|
|
|
|
#undef __LICE__ACTION
|
|
|
|
#ifdef LICE_FAVOR_SIZE
|
|
if (blitfunc) _LICE_Template_Blit2::blit(pdest,psrc,cpsize,i,src_span,dest_span,ia,blitfunc);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void LICE_Blit(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, const RECT *srcrect, float alpha, int mode)
|
|
{
|
|
LICE_BlitInt(dest,src,dstx,dsty,srcrect,alpha,mode,true);
|
|
}
|
|
|
|
void LICE_Blit(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch, float alpha, int mode)
|
|
{
|
|
RECT r={srcx,srcy,srcx+srcw,srcy+srch};
|
|
LICE_BlitInt(dest,src,dstx,dsty,&r,alpha,mode,true);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef LICE_NO_BLUR_SUPPORT
|
|
|
|
void LICE_Blur(LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch) // src and dest can overlap, however it may look fudgy if they do
|
|
{
|
|
if (!dest || !src) return;
|
|
|
|
RECT sr={srcx,srcy,srcx+srcw,srcy+srch};
|
|
if (sr.left < 0) sr.left=0;
|
|
if (sr.top < 0) sr.top=0;
|
|
if (sr.right > src->getWidth()) sr.right=src->getWidth();
|
|
if (sr.bottom > src->getHeight()) sr.bottom = src->getHeight();
|
|
|
|
// clip to output
|
|
if (dstx < 0) { sr.left -= dstx; dstx=0; }
|
|
if (dsty < 0) { sr.top -= dsty; dsty=0; }
|
|
|
|
if (sr.left < 0 || sr.top < 0) return; // overflow check
|
|
|
|
const int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
if (sr.right <= sr.left || sr.bottom <= sr.top || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (sr.right > sr.left + (destbm_w-dstx)) sr.right = sr.left + (destbm_w-dstx);
|
|
if (sr.bottom > sr.top + (destbm_h-dsty)) sr.bottom = sr.top + (destbm_h-dsty);
|
|
|
|
// ignore blits that are smaller than 2x2
|
|
if (sr.right <= sr.left+1 || sr.bottom <= sr.top+1) return;
|
|
|
|
int dest_span=dest->getRowSpan();
|
|
int src_span=src->getRowSpan();
|
|
const LICE_pixel *psrc = (LICE_pixel *)src->getBits();
|
|
LICE_pixel *pdest = (LICE_pixel *)dest->getBits();
|
|
if (!psrc || !pdest) return;
|
|
|
|
if (src->isFlipped())
|
|
{
|
|
psrc += (src->getHeight()-sr.top - 1)*src_span;
|
|
src_span=-src_span;
|
|
}
|
|
else psrc += sr.top*src_span;
|
|
psrc += sr.left;
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else pdest += dsty*dest_span;
|
|
pdest+=dstx;
|
|
|
|
LICE_pixel *tmpbuf=NULL;
|
|
int w=sr.right-sr.left;
|
|
|
|
// buffer to save the last unprocessed lines for the cases where blurring from a bitmap to itself
|
|
LICE_pixel turdbuf[2048];
|
|
if (src==dest)
|
|
{
|
|
if (w <= (int) (sizeof(turdbuf)/sizeof(turdbuf[0])/2)) tmpbuf=turdbuf;
|
|
else tmpbuf=(LICE_pixel*)malloc(w*2*sizeof(LICE_pixel));
|
|
}
|
|
|
|
int i;
|
|
for (i = sr.top; i < sr.bottom; i ++)
|
|
{
|
|
if (tmpbuf)
|
|
memcpy(tmpbuf+((i&1)?w:0),psrc,w*sizeof(LICE_pixel));
|
|
|
|
if (i==sr.top || i==sr.bottom-1)
|
|
{
|
|
const LICE_pixel *psrc2=psrc+(i==sr.top ? src_span : -src_span);
|
|
|
|
LICE_pixel lp;
|
|
|
|
pdest[0] = LICE_PIXEL_HALF(lp=psrc[0]) +
|
|
LICE_PIXEL_QUARTER(psrc[1]) +
|
|
LICE_PIXEL_QUARTER(psrc2[0]);
|
|
int x;
|
|
for (x = 1; x < w-1; x ++)
|
|
{
|
|
LICE_pixel tp;
|
|
pdest[x] = LICE_PIXEL_HALF(tp=psrc[x]) +
|
|
LICE_PIXEL_QUARTER(psrc2[x]) +
|
|
LICE_PIXEL_EIGHTH(psrc[x+1]) +
|
|
LICE_PIXEL_EIGHTH(lp);
|
|
lp=tp;
|
|
}
|
|
pdest[x] = LICE_PIXEL_HALF(psrc[x]) +
|
|
LICE_PIXEL_QUARTER(lp) +
|
|
LICE_PIXEL_QUARTER(psrc2[x]);
|
|
}
|
|
else
|
|
{
|
|
const LICE_pixel *psrc2=psrc-src_span;
|
|
const LICE_pixel *psrc3=psrc+src_span;
|
|
if (tmpbuf)
|
|
psrc2=tmpbuf + ((i&1) ? 0 : w);
|
|
|
|
LICE_pixel lp;
|
|
pdest[0] = LICE_PIXEL_HALF(lp=psrc[0]) +
|
|
LICE_PIXEL_QUARTER(psrc[1]) +
|
|
LICE_PIXEL_EIGHTH(psrc2[0]) +
|
|
LICE_PIXEL_EIGHTH(psrc3[0]);
|
|
int x;
|
|
for (x = 1; x < w-1; x ++)
|
|
{
|
|
LICE_pixel tp;
|
|
pdest[x] = LICE_PIXEL_HALF(tp=psrc[x]) +
|
|
LICE_PIXEL_EIGHTH(psrc[x+1]) +
|
|
LICE_PIXEL_EIGHTH(lp) +
|
|
LICE_PIXEL_EIGHTH(psrc2[x]) +
|
|
LICE_PIXEL_EIGHTH(psrc3[x]);
|
|
lp=tp;
|
|
}
|
|
pdest[x] = LICE_PIXEL_HALF(psrc[x]) +
|
|
LICE_PIXEL_QUARTER(lp) +
|
|
LICE_PIXEL_EIGHTH(psrc2[x]) +
|
|
LICE_PIXEL_EIGHTH(psrc3[x]);
|
|
}
|
|
pdest+=dest_span;
|
|
psrc += src_span;
|
|
}
|
|
if (tmpbuf && tmpbuf != turdbuf)
|
|
free(tmpbuf);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef LICE_NO_BLIT_SUPPORT
|
|
void LICE_ScaledBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
float srcx, float srcy, float srcw, float srch,
|
|
float alpha, int mode)
|
|
{
|
|
if (!dest || !src || !dstw || !dsth || !alpha) return;
|
|
|
|
int srcbm_w = src->getWidth(), srcbm_h = src->getHeight();
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
const float srcx_orig = srcx, srcy_orig = srcy, srcw_orig = srcw, srch_orig = srch;
|
|
const int dstx_orig = dstx, dsty_orig = dsty;
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(dstx);
|
|
__LICE_SC(dsty);
|
|
__LICE_SC(dstw);
|
|
__LICE_SC(dsth);
|
|
}
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
}
|
|
__sc = (int)src->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(srcx);
|
|
__LICE_SC(srcy);
|
|
__LICE_SC(srcw);
|
|
__LICE_SC(srch);
|
|
}
|
|
__LICE_SCU(srcbm_w);
|
|
__LICE_SCU(srcbm_h);
|
|
}
|
|
|
|
// non-scaling optimized omde
|
|
if (fabs(srcw-dstw)<0.001 && fabs(srch-dsth)<0.001)
|
|
{
|
|
// and if not bilinear filtering, or
|
|
// the source coordinates are near their integer counterparts
|
|
if ((mode&LICE_BLIT_FILTER_MASK)!=LICE_BLIT_FILTER_BILINEAR ||
|
|
(fabs(srcx-floor(srcx+0.5f))<0.03 && fabs(srcy-floor(srcy+0.5f))<0.03))
|
|
{
|
|
RECT sr={(int)(srcx_orig+0.5f),(int)(srcy_orig+0.5f),};
|
|
sr.right=sr.left+(int) (srcw_orig+0.5);
|
|
sr.bottom=sr.top+(int) (srch_orig+0.5);
|
|
LICE_BlitInt(dest,src,dstx_orig,dsty_orig,&sr,alpha,mode,false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_SCALEDBLIT_ACCEL))
|
|
{
|
|
LICE_Ext_ScaledBlit_acceldata data(src, dstx, dsty, dstw, dsth, srcx, srcy, srcw, srch, alpha, mode);
|
|
if (dest->Extended(LICE_EXT_SCALEDBLIT_ACCEL, &data)) return;
|
|
}
|
|
#endif
|
|
|
|
if (dstw<0)
|
|
{
|
|
dstw=-dstw;
|
|
dstx-=dstw;
|
|
srcx+=srcw;
|
|
srcw=-srcw;
|
|
}
|
|
if (dsth<0)
|
|
{
|
|
dsth=-dsth;
|
|
dsty-=dsth;
|
|
srcy+=srch;
|
|
srch=-srch;
|
|
}
|
|
|
|
double xadvance = srcw / dstw;
|
|
double yadvance = srch / dsth;
|
|
|
|
int clip_r=(int)(srcx+lice_max(srcw,0)+0.999999); // this rounding logic is shit, but we're stuck with it
|
|
int clip_b=(int)(srcy+lice_max(srch,0)+0.999999);
|
|
if (clip_r>srcbm_w) clip_r=srcbm_w;
|
|
if (clip_b>srcbm_h) clip_b=srcbm_h;
|
|
|
|
|
|
if (dstx < 0) { srcx -= (float) (dstx*xadvance); dstw+=dstx; dstx=0; }
|
|
if (dsty < 0) { srcy -= (float) (dsty*yadvance); dsth+=dsty; dsty=0; }
|
|
|
|
if (dstw < 1 || dsth < 1 || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (dstw > destbm_w-dstx) dstw=destbm_w-dstx;
|
|
if (dsth > destbm_h-dsty) dsth=destbm_h-dsty;
|
|
|
|
const double fidx=floor(xadvance*65536.0), fidy=floor(yadvance*65536.0);
|
|
|
|
double ficurx=floor(srcx*65536.0), ficury=floor(srcy*65536.0);
|
|
|
|
// the clip area calculations need to be done fixed point so the results match runtime
|
|
|
|
if (fidx>0)
|
|
{
|
|
if (ficurx < 0) // increase dstx, decrease dstw
|
|
{
|
|
int n = (int)((fidx-1-ficurx)/fidx);
|
|
dstw-=n;
|
|
dstx+=n;
|
|
ficurx+=fidx*n;
|
|
}
|
|
if ((ficurx + fidx*(dstw-1)) >= srcbm_w*65536.0)
|
|
{
|
|
int neww = (int)(((srcbm_w-1)*65536.0 - ficurx)/fidx);
|
|
if (neww < dstw) dstw=neww;
|
|
}
|
|
}
|
|
else if (fidx<0)
|
|
{
|
|
// todo: optimize source-clipping with reversed X axis
|
|
}
|
|
|
|
if (fidy > 0)
|
|
{
|
|
if (ficury < 0) // increase dsty, decrease dsth
|
|
{
|
|
int n = (int) ((fidy-1-ficury)/fidy);
|
|
dsth-=n;
|
|
dsty+=n;
|
|
ficury+=fidy*n;
|
|
}
|
|
if ((ficury + fidy*(dsth-1)) >= srcbm_h*65536.0)
|
|
{
|
|
int newh = (int)(((srcbm_h-1)*65536.0 - ficury)/fidy);
|
|
if (newh < dsth) dsth=newh;
|
|
}
|
|
}
|
|
else if (fidy<0)
|
|
{
|
|
// todo: optimize source-clipping with reversed Y axis (check icury against src->getHeight(), etc)
|
|
}
|
|
if (dstw<1 || dsth<1) return;
|
|
|
|
int dest_span=dest->getRowSpan()*sizeof(LICE_pixel);
|
|
int src_span=src->getRowSpan()*sizeof(LICE_pixel);
|
|
|
|
const LICE_pixel_chan *psrc = (const LICE_pixel_chan *)src->getBits();
|
|
LICE_pixel_chan *pdest = (LICE_pixel_chan *)dest->getBits();
|
|
if (!psrc || !pdest) return;
|
|
|
|
const int srcoffs_x = (int)((ficurx + (fidx<0 ? fidx*dstw : 0))*(1.0/65536.0));
|
|
const int srcoffs_y = (int)((ficury + (fidy<0 ? fidy*dsth : 0))*(1.0/65536.0));
|
|
|
|
if (src->isFlipped())
|
|
{
|
|
psrc += (srcbm_h-1-srcoffs_y)*src_span;
|
|
src_span=-src_span;
|
|
}
|
|
else psrc += srcoffs_y * src_span;
|
|
psrc += srcoffs_x * sizeof(LICE_pixel);
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else pdest += dsty*dest_span;
|
|
pdest+=dstx*sizeof(LICE_pixel);
|
|
|
|
clip_r -= srcoffs_x;
|
|
clip_b -= srcoffs_y;
|
|
|
|
const int icurx = (int) (ficurx - srcoffs_x*65536.0);
|
|
const int icury = (int) (ficury - srcoffs_y*65536.0);
|
|
const int idx = (int) fidx, idy = (int) fidy;
|
|
|
|
if (clip_r<1||clip_b<1) return;
|
|
|
|
int ia=(int)(alpha*256.0);
|
|
|
|
if ((mode&(LICE_BLIT_FILTER_MASK|LICE_BLIT_MODE_MASK|LICE_BLIT_USE_ALPHA))==LICE_BLIT_MODE_COPY && (ia==128 || ia==256))
|
|
{
|
|
if (ia==128)
|
|
{
|
|
_LICE_Template_Blit0<_LICE_CombinePixelsHalfMixFAST>::scaleBlitFAST(pdest,psrc,dstw,dsth,icurx,icury,idx,idy,clip_r,clip_b,src_span,dest_span);
|
|
}
|
|
else
|
|
{
|
|
_LICE_Template_Blit0<_LICE_CombinePixelsClobberFAST>::scaleBlitFAST(pdest,psrc,dstw,dsth,icurx,icury,idx,idy,clip_r,clip_b,src_span,dest_span);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xadvance>=1.7 && yadvance >=1.7 && (mode&LICE_BLIT_FILTER_MASK)==LICE_BLIT_FILTER_BILINEAR)
|
|
{
|
|
int msc = lice_max(idx,idy);
|
|
const int filtsz=msc>(3<<16) ? 5 : 3;
|
|
const int filt_start = - (filtsz/2);
|
|
|
|
int filter[25]; // 5x5 max
|
|
{
|
|
int y;
|
|
// char buf[4096];
|
|
// sprintf(buf,"filter, msc=%f: ",msc);
|
|
int *p=filter;
|
|
for(y=0;y<filtsz;y++)
|
|
{
|
|
int x;
|
|
for(x=0;x<filtsz;x++)
|
|
{
|
|
if (x==y && x==filtsz/2) *p++ = 65536; // src pix is always valued at 1.
|
|
else
|
|
{
|
|
double dx=x+filt_start;
|
|
double dy=y+filt_start;
|
|
double v = (msc-1.0) / sqrt(dx*dx+dy*dy); // this needs serious tweaking...
|
|
|
|
// sprintf(buf+strlen(buf),"%f,",v);
|
|
|
|
if(v<0.0) *p++=0;
|
|
else if (v>1.0) *p++=65536;
|
|
else *p++=(int)(v*65536.0);
|
|
}
|
|
}
|
|
}
|
|
// OutputDebugString(buf);
|
|
}
|
|
|
|
#ifdef LICE_FAVOR_SIZE
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc=comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit2<comb>::scaleBlitFilterDown(pdest,psrc,dstw,dsth,icurx,icury,idx,idy,clip_r,clip_b,src_span,dest_span,ia,filter,filt_start,filtsz)
|
|
#endif
|
|
__LICE_ACTION_SRCALPHA(mode,ia,false);
|
|
#undef __LICE__ACTION
|
|
|
|
#ifdef LICE_FAVOR_SIZE
|
|
if (blitfunc) _LICE_Template_Blit2::scaleBlitFilterDown(pdest,psrc,dstw,dsth,icurx,icury,idx,idy,clip_r,clip_b,src_span,dest_span,ia,filter,filt_start,filtsz,blitfunc);
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
#ifdef LICE_FAVOR_SIZE
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc=comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit2<comb>::scaleBlit(pdest,psrc,dstw,dsth,icurx,icury,idx,idy,clip_r,clip_b,src_span,dest_span,ia,mode&LICE_BLIT_FILTER_MASK)
|
|
#endif
|
|
__LICE_ACTION_SRCALPHA(mode,ia,false);
|
|
#undef __LICE__ACTION
|
|
#ifdef LICE_FAVOR_SIZE
|
|
if (blitfunc) _LICE_Template_Blit2::scaleBlit(pdest,psrc,dstw,dsth,icurx,icury,idx,idy,clip_r,clip_b,src_span,dest_span,ia,mode&LICE_BLIT_FILTER_MASK,blitfunc);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void LICE_DeltaBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
float srcx, float srcy, float srcw, float srch,
|
|
double dsdx, double dtdx, double dsdy, double dtdy,
|
|
double dsdxdy, double dtdxdy,
|
|
bool cliptosourcerect, float alpha, int mode)
|
|
{
|
|
if (!dest || !src || !dstw || !dsth) return;
|
|
|
|
int srcbm_w = src->getWidth(), srcbm_h = src->getHeight();
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
|
|
int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(dstx);
|
|
__LICE_SC(dsty);
|
|
__LICE_SC(dstw);
|
|
__LICE_SC(dsth);
|
|
}
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
|
|
}
|
|
const int __scdest = __sc;
|
|
__sc = (int)src->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(srcx);
|
|
__LICE_SC(srcy);
|
|
__LICE_SC(srcw);
|
|
__LICE_SC(srch);
|
|
}
|
|
__LICE_SCU(srcbm_w);
|
|
__LICE_SCU(srcbm_h);
|
|
}
|
|
|
|
if (__scdest != __sc && !IGNORE_SCALING(mode))
|
|
{
|
|
const double adj = (__sc>0 ? __sc : 256.0) / (double) (__scdest>0 ? __scdest : 256.0);
|
|
dsdx *= adj;
|
|
dtdx *= adj;
|
|
dsdy *= adj;
|
|
dtdy *= adj;
|
|
dsdxdy *= adj;
|
|
dtdxdy *= adj;
|
|
}
|
|
|
|
double src_top=0.0,src_left=0.0,src_right=srcbm_w,src_bottom=srcbm_h;
|
|
|
|
if (cliptosourcerect)
|
|
{
|
|
if (srcx > src_left) src_left=srcx;
|
|
if (srcy > src_top) src_top=srcy;
|
|
if (srcx+srcw < src_right) src_right=srcx+srcw;
|
|
if (srcy+srch < src_bottom) src_bottom=srcy+srch;
|
|
}
|
|
|
|
if (dstw<0)
|
|
{
|
|
dstw=-dstw;
|
|
dstx-=dstw;
|
|
srcx+=srcw;
|
|
}
|
|
if (dsth<0)
|
|
{
|
|
dsth=-dsth;
|
|
dsty-=dsth;
|
|
srcy+=srch;
|
|
}
|
|
|
|
|
|
if (dstx < 0)
|
|
{
|
|
srcx -= (float) (dstx*dsdx);
|
|
srcy -= (float) (dstx*dtdx);
|
|
dstw+=dstx;
|
|
dstx=0;
|
|
}
|
|
if (dsty < 0)
|
|
{
|
|
srcy -= (float) (dsty*dtdy);
|
|
srcx -= (float) (dsty*dsdy);
|
|
dsth+=dsty;
|
|
dsty=0;
|
|
}
|
|
|
|
if (dstw < 1 || dsth < 1 || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (dstw > destbm_w-dstx) dstw=destbm_w-dstx;
|
|
if (dsth > destbm_h-dsty) dsth=destbm_h-dsty;
|
|
|
|
|
|
int dest_span=dest->getRowSpan()*sizeof(LICE_pixel);
|
|
int src_span=src->getRowSpan()*sizeof(LICE_pixel);
|
|
|
|
const LICE_pixel_chan *psrc = (LICE_pixel_chan *)src->getBits();
|
|
LICE_pixel_chan *pdest = (LICE_pixel_chan *)dest->getBits();
|
|
if (!psrc || !pdest) return;
|
|
|
|
if (src->isFlipped())
|
|
{
|
|
psrc += (srcbm_h-1)*src_span;
|
|
src_span=-src_span;
|
|
}
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else pdest += dsty*dest_span;
|
|
pdest+=dstx*sizeof(LICE_pixel);
|
|
|
|
int sl=(int)(src_left);
|
|
int sr=(int)(src_right);
|
|
int st=(int)(src_top);
|
|
int sb=(int)(src_bottom);
|
|
|
|
sr -= sl;
|
|
sb -= st;
|
|
if (sr < 1 || sb < 1) return;
|
|
|
|
psrc += src_span * st + sl * sizeof(LICE_pixel);
|
|
|
|
int ia=(int)(alpha*256.0);
|
|
int isrcx=(int)(srcx*65536.0);
|
|
int isrcy=(int)(srcy*65536.0);
|
|
int idsdx=(int)(dsdx*65536.0);
|
|
int idtdx=(int)(dtdx*65536.0);
|
|
int idsdy=(int)(dsdy*65536.0);
|
|
int idtdy=(int)(dtdy*65536.0);
|
|
int idsdxdy=(int)(dsdxdy*65536.0);
|
|
int idtdxdy=(int)(dtdxdy*65536.0);
|
|
|
|
#ifndef LICE_FAVOR_SPEED
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc = comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit3<comb>::deltaBlit(pdest,psrc,dstw,dsth,isrcx,isrcy,idsdx,idtdx,idsdy,idtdy,idsdxdy,idtdxdy,sr,sb,src_span,dest_span,ia,mode&LICE_BLIT_FILTER_MASK)
|
|
#endif
|
|
__LICE_ACTION_SRCALPHA(mode,ia,false);
|
|
#undef __LICE__ACTION
|
|
|
|
#ifndef LICE_FAVOR_SPEED
|
|
if (blitfunc) _LICE_Template_Blit3::deltaBlit(pdest,psrc,dstw,dsth,isrcx,isrcy,idsdx,idtdx,idsdy,idtdy,idsdxdy,idtdxdy,sr,sb,src_span,dest_span,ia,mode&LICE_BLIT_FILTER_MASK,blitfunc);
|
|
#endif
|
|
|
|
}
|
|
|
|
void LICE_DeltaBlitAlpha(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
float srcx, float srcy, float srcw, float srch,
|
|
double dsdx, double dtdx, double dsdy, double dtdy,
|
|
double dsdxdy, double dtdxdy,
|
|
bool cliptosourcerect, float alpha, int mode, double dadx, double dady, double dadxdy)
|
|
{
|
|
if (!dest || !src || !dstw || !dsth) return;
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
int srcbm_w = src->getWidth(), srcbm_h = src->getHeight();
|
|
int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(dstx);
|
|
__LICE_SC(dsty);
|
|
__LICE_SC(dstw);
|
|
__LICE_SC(dsth);
|
|
}
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
|
|
}
|
|
const int __scdest = __sc;
|
|
__sc = (int)src->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(srcx);
|
|
__LICE_SC(srcy);
|
|
__LICE_SC(srcw);
|
|
__LICE_SC(srch);
|
|
}
|
|
__LICE_SCU(srcbm_w);
|
|
__LICE_SCU(srcbm_h);
|
|
}
|
|
|
|
if (lice_max(__scdest,0) != lice_max(__sc,0))
|
|
{
|
|
const double adj = (__sc>0 ? __sc : 256.0) / (double) (__scdest>0 ? __scdest : 256.0);
|
|
dsdx *= adj;
|
|
dtdx *= adj;
|
|
dadx *= adj;
|
|
dsdy *= adj;
|
|
dtdy *= adj;
|
|
dady *= adj;
|
|
dsdxdy *= adj;
|
|
dtdxdy *= adj;
|
|
dadxdy *= adj;
|
|
}
|
|
|
|
const double eps = 0.0001;
|
|
if (fabs(dadx*dstw) < eps && fabs(dady*dsth) < eps && fabs(dadxdy*dsth) < eps)
|
|
{
|
|
LICE_DeltaBlit(dest, src, dstx, dsty, dstw, dsth, srcx, srcy, srcw, srch, dsdx, dtdx, dsdy, dtdy, dsdxdy, dtdxdy, cliptosourcerect, alpha, mode);
|
|
return;
|
|
}
|
|
|
|
double src_top=0.0,src_left=0.0,src_right=srcbm_w,src_bottom=srcbm_h;
|
|
|
|
if (cliptosourcerect)
|
|
{
|
|
if (srcx > src_left) src_left=srcx;
|
|
if (srcy > src_top) src_top=srcy;
|
|
if (srcx+srcw < src_right) src_right=srcx+srcw;
|
|
if (srcy+srch < src_bottom) src_bottom=srcy+srch;
|
|
}
|
|
|
|
if (dstw<0)
|
|
{
|
|
dstw=-dstw;
|
|
dstx-=dstw;
|
|
srcx+=srcw;
|
|
}
|
|
if (dsth<0)
|
|
{
|
|
dsth=-dsth;
|
|
dsty-=dsth;
|
|
srcy+=srch;
|
|
}
|
|
|
|
|
|
if (dstx < 0)
|
|
{
|
|
alpha -= (float) (dstx*dadx);
|
|
srcx -= (float) (dstx*dsdx);
|
|
srcy -= (float) (dstx*dtdx);
|
|
dstw+=dstx;
|
|
dstx=0;
|
|
}
|
|
if (dsty < 0)
|
|
{
|
|
alpha -= (float) (dsty*dady);
|
|
srcy -= (float) (dsty*dtdy);
|
|
srcx -= (float) (dsty*dsdy);
|
|
dsth+=dsty;
|
|
dsty=0;
|
|
}
|
|
|
|
if (dstw < 1 || dsth < 1 || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (dstw > destbm_w-dstx) dstw=destbm_w-dstx;
|
|
if (dsth > destbm_h-dsty) dsth=destbm_h-dsty;
|
|
|
|
|
|
int dest_span=dest->getRowSpan()*sizeof(LICE_pixel);
|
|
int src_span=src->getRowSpan()*sizeof(LICE_pixel);
|
|
|
|
const LICE_pixel_chan *psrc = (LICE_pixel_chan *)src->getBits();
|
|
LICE_pixel_chan *pdest = (LICE_pixel_chan *)dest->getBits();
|
|
if (!psrc || !pdest) return;
|
|
|
|
if (src->isFlipped())
|
|
{
|
|
psrc += (srcbm_h-1)*src_span;
|
|
src_span=-src_span;
|
|
}
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else pdest += dsty*dest_span;
|
|
pdest+=dstx*sizeof(LICE_pixel);
|
|
|
|
int sl=(int)(src_left);
|
|
int sr=(int)(src_right);
|
|
int st=(int)(src_top);
|
|
int sb=(int)(src_bottom);
|
|
|
|
sr -= sl;
|
|
sb -= st;
|
|
if (sr < 1 || sb < 1) return;
|
|
|
|
psrc += src_span * st + sl * sizeof(LICE_pixel);
|
|
|
|
int ia=(int)(alpha*65536.0);
|
|
int isrcx=(int)(srcx*65536.0);
|
|
int isrcy=(int)(srcy*65536.0);
|
|
int idsdx=(int)(dsdx*65536.0);
|
|
int idtdx=(int)(dtdx*65536.0);
|
|
int idsdy=(int)(dsdy*65536.0);
|
|
int idtdy=(int)(dtdy*65536.0);
|
|
int idsdxdy=(int)(dsdxdy*65536.0);
|
|
int idtdxdy=(int)(dtdxdy*65536.0);
|
|
|
|
int idadx=(int)(dadx*65536.0);
|
|
int idady=(int)(dady*65536.0);
|
|
int idadxdy=(int)(dadxdy*65536.0);
|
|
|
|
#ifndef LICE_FAVOR_SPEED
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc = comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit4<comb>::deltaBlitAlpha(pdest,psrc,dstw,dsth,isrcx,isrcy,idsdx,idtdx,idsdy,idtdy,idsdxdy,idtdxdy,sr,sb,src_span,dest_span,ia,idadx,idady,idadxdy,mode&LICE_BLIT_FILTER_MASK)
|
|
#endif
|
|
__LICE_ACTION_NOSRCALPHA(mode,256,true);
|
|
#undef __LICE__ACTION
|
|
|
|
#ifndef LICE_FAVOR_SPEED
|
|
if (blitfunc) _LICE_Template_Blit4::deltaBlitAlpha(pdest,psrc,dstw,dsth,isrcx,isrcy,idsdx,idtdx,idsdy,idtdy,idsdxdy,idtdxdy,sr,sb,src_span,dest_span,ia,idadx,idady,idadxdy,mode&LICE_BLIT_FILTER_MASK,blitfunc);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LICE_RotatedBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
float srcx, float srcy, float srcw, float srch,
|
|
float angle,
|
|
bool cliptosourcerect, float alpha, int mode, float rotxcent, float rotycent)
|
|
{
|
|
if (!dest || !src || !dstw || !dsth) return;
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
int srcbm_w = src->getWidth(), srcbm_h = src->getHeight();
|
|
int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(dstx);
|
|
__LICE_SC(dsty);
|
|
__LICE_SC(dstw);
|
|
__LICE_SC(dsth);
|
|
}
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
|
|
}
|
|
__sc = (int)src->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SC(srcx);
|
|
__LICE_SC(srcy);
|
|
__LICE_SC(srcw);
|
|
__LICE_SC(srch);
|
|
}
|
|
__LICE_SCU(srcbm_w);
|
|
__LICE_SCU(srcbm_h);
|
|
}
|
|
double src_top=0.0,src_left=0.0,src_right=srcbm_w,src_bottom=srcbm_h;
|
|
|
|
if (cliptosourcerect)
|
|
{
|
|
if (srcx > src_left) src_left=srcx;
|
|
if (srcy > src_top) src_top=srcy;
|
|
if (srcx+srcw < src_right) src_right=srcx+srcw;
|
|
if (srcy+srch < src_bottom) src_bottom=srcy+srch;
|
|
}
|
|
|
|
if (dstw<0)
|
|
{
|
|
dstw=-dstw;
|
|
dstx-=dstw;
|
|
srcx+=srcw;
|
|
srcw=-srcw;
|
|
}
|
|
if (dsth<0)
|
|
{
|
|
dsth=-dsth;
|
|
dsty-=dsth;
|
|
srcy+=srch;
|
|
srch=-srch;
|
|
}
|
|
|
|
double cosa=cos(angle);
|
|
double sina=sin(angle);
|
|
|
|
double xsc=srcw / dstw;
|
|
double ysc=srch / dsth;
|
|
|
|
double dsdx = xsc * cosa;
|
|
double dtdy = ysc * cosa;
|
|
double dsdy = xsc * sina;
|
|
double dtdx = ysc * -sina;
|
|
|
|
srcx -= (float) (0.5 * (dstw*dsdx + dsth*dsdy - srcw) - rotxcent);
|
|
srcy -= (float) (0.5 * (dsth*dtdy + dstw*dtdx - srch) - rotycent);
|
|
|
|
if (dstx < 0)
|
|
{
|
|
srcx -= (float) (dstx*dsdx);
|
|
srcy -= (float) (dstx*dtdx);
|
|
dstw+=dstx;
|
|
dstx=0;
|
|
}
|
|
if (dsty < 0)
|
|
{
|
|
srcy -= (float) (dsty*dtdy);
|
|
srcx -= (float) (dsty*dsdy);
|
|
dsth+=dsty;
|
|
dsty=0;
|
|
}
|
|
|
|
if (dstw < 1 || dsth < 1 || dstx >= destbm_w || dsty >= destbm_h) return;
|
|
|
|
if (dstw > destbm_w-dstx) dstw=destbm_w-dstx;
|
|
if (dsth > destbm_h-dsty) dsth=destbm_h-dsty;
|
|
|
|
|
|
int dest_span=dest->getRowSpan()*sizeof(LICE_pixel);
|
|
int src_span=src->getRowSpan()*sizeof(LICE_pixel);
|
|
|
|
const LICE_pixel_chan *psrc = (LICE_pixel_chan *)src->getBits();
|
|
LICE_pixel_chan *pdest = (LICE_pixel_chan *)dest->getBits();
|
|
if (!psrc || !pdest) return;
|
|
|
|
if (src->isFlipped())
|
|
{
|
|
psrc += (srcbm_h-1)*src_span;
|
|
src_span=-src_span;
|
|
}
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
pdest += (destbm_h-dsty - 1)*dest_span;
|
|
dest_span=-dest_span;
|
|
}
|
|
else pdest += dsty*dest_span;
|
|
pdest+=dstx*sizeof(LICE_pixel);
|
|
|
|
int sl=(int)(src_left);
|
|
int sr=(int)(src_right);
|
|
int st=(int)(src_top);
|
|
int sb=(int)(src_bottom);
|
|
|
|
sr -= sl;
|
|
sb -= st;
|
|
srcx -= sl;
|
|
srcy -= st;
|
|
if (sr < 1 || sb < 1) return;
|
|
|
|
psrc += src_span * st + sl * sizeof(LICE_pixel);
|
|
|
|
int ia=(int)(alpha*256.0);
|
|
int isrcx=(int)(srcx*65536.0);
|
|
int isrcy=(int)(srcy*65536.0);
|
|
int idsdx=(int)(dsdx*65536.0);
|
|
int idtdx=(int)(dtdx*65536.0);
|
|
int idsdy=(int)(dsdy*65536.0);
|
|
int idtdy=(int)(dtdy*65536.0);
|
|
|
|
#ifndef LICE_FAVOR_SPEED
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc = comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit3<comb>::deltaBlit(pdest,psrc,dstw,dsth,isrcx,isrcy,idsdx,idtdx,idsdy,idtdy,0,0,sr,sb,src_span,dest_span,ia,mode&LICE_BLIT_FILTER_MASK)
|
|
#endif
|
|
__LICE_ACTION_SRCALPHA(mode,ia,false);
|
|
#undef __LICE__ACTION
|
|
|
|
#ifndef LICE_FAVOR_SPEED
|
|
if (blitfunc) _LICE_Template_Blit3::deltaBlit(pdest,psrc,dstw,dsth,isrcx,isrcy,idsdx,idtdx,idsdy,idtdy,0,0,sr,sb,src_span,dest_span,ia,mode&LICE_BLIT_FILTER_MASK,blitfunc);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void LICE_Clear(LICE_IBitmap *dest, LICE_pixel color)
|
|
{
|
|
if (!dest) return;
|
|
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_CLEAR_ACCEL))
|
|
{
|
|
if (dest->Extended(LICE_EXT_CLEAR_ACCEL, &color)) return;
|
|
}
|
|
#endif
|
|
|
|
LICE_pixel *p=dest->getBits();
|
|
int h=dest->getHeight();
|
|
int w=dest->getWidth();
|
|
const int sp=dest->getRowSpan();
|
|
|
|
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
__LICE_SCU(w);
|
|
__LICE_SCU(h);
|
|
}
|
|
|
|
if (!p || w<1 || h<1 || !sp) return;
|
|
|
|
while (h-->0)
|
|
{
|
|
int n=w;
|
|
while (n--) *p++ = color;
|
|
p+=sp-w;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void LICE_MultiplyAddRect(LICE_IBitmap *dest, int x, int y, int w, int h,
|
|
float rsc, float gsc, float bsc, float asc,
|
|
float radd, float gadd, float badd, float aadd)
|
|
{
|
|
if (!dest) return;
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
DO_RECT_SC(0)
|
|
|
|
if (x<0) { w+=x; x=0; }
|
|
if (y<0) { h+=y; y=0; }
|
|
|
|
LICE_pixel *p=dest->getBits();
|
|
const int sp=dest->getRowSpan();
|
|
if (!p || !sp || w<1 || h < 1 || x >= destbm_w || y >= destbm_h) return;
|
|
|
|
if (w>destbm_w-x) w=destbm_w-x;
|
|
if (h>destbm_h-y) h=destbm_h-y;
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
p+=(destbm_h - y - h)*sp;
|
|
}
|
|
else
|
|
{
|
|
p+=sp*y;
|
|
}
|
|
|
|
p += x;
|
|
|
|
int ir=(int)(rsc*256.0);
|
|
int ig=(int)(gsc*256.0);
|
|
int ib=(int)(bsc*256.0);
|
|
int ia=(int)(asc*256.0);
|
|
int ir2=(int)(radd*256.0);
|
|
int ig2=(int)(gadd*256.0);
|
|
int ib2=(int)(badd*256.0);
|
|
int ia2=(int)(aadd*256.0);
|
|
|
|
while (h-->0)
|
|
{
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
LICE_pixel_chan *ptr=(LICE_pixel_chan *)p++;
|
|
_LICE_MakePixelClamp(ptr,(ptr[LICE_PIXEL_R]*ir+ir2)>>8,
|
|
(ptr[LICE_PIXEL_G]*ig+ig2)>>8,
|
|
(ptr[LICE_PIXEL_B]*ib+ib2)>>8,
|
|
(ptr[LICE_PIXEL_A]*ia+ia2)>>8);
|
|
}
|
|
p+=sp-w;
|
|
}
|
|
}
|
|
|
|
void LICE_ProcessRect(LICE_IBitmap *dest, int x, int y, int w, int h, void (*procFunc)(LICE_pixel *p, void *parm), void *parm)
|
|
{
|
|
if (!dest||!procFunc) return;
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
DO_RECT_SC(0)
|
|
|
|
if (x<0) { w+=x; x=0; }
|
|
if (y<0) { h+=y; y=0; }
|
|
|
|
LICE_pixel *p=dest->getBits();
|
|
const int sp=dest->getRowSpan();
|
|
|
|
if (!p || !sp || w<1 || h < 1 || x >= destbm_w || y >= destbm_h) return;
|
|
|
|
if (w>destbm_w-x) w=destbm_w-x;
|
|
if (h>destbm_h-y) h=destbm_h-y;
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
p+=(destbm_h - y - h)*sp;
|
|
}
|
|
else
|
|
{
|
|
p+=sp*y;
|
|
}
|
|
|
|
p += x;
|
|
|
|
while (h--)
|
|
{
|
|
LICE_pixel *pout=p;
|
|
int n=w;
|
|
while (n-->0) procFunc(pout++,parm);
|
|
p+=sp;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void LICE_FillRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel color, float alpha, int mode)
|
|
{
|
|
if (!dest) return;
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
DO_RECT_SC(mode)
|
|
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_FILLRECT_ACCEL))
|
|
{
|
|
LICE_Ext_FillRect_acceldata data(x, y, w, h, color, alpha, mode);
|
|
if (dest->Extended(LICE_EXT_FILLRECT_ACCEL, &data)) return;
|
|
}
|
|
#endif
|
|
|
|
if (mode & LICE_BLIT_USE_ALPHA) alpha *= LICE_GETA(color)/255.0f;
|
|
|
|
LICE_pixel *p=dest->getBits();
|
|
const int sp=dest->getRowSpan();
|
|
|
|
if (x<0) { w+=x; x=0; }
|
|
if (y<0) { h+=y; y=0; }
|
|
if (!alpha || !p || !sp || w<1 || h < 1 || x >= destbm_w || y >= destbm_h) return;
|
|
|
|
if (w>destbm_w-x) w=destbm_w-x;
|
|
if (h>destbm_h-y) h=destbm_h-y;
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
p+=(destbm_h - y - h)*sp;
|
|
}
|
|
else
|
|
{
|
|
p+=sp*y;
|
|
}
|
|
|
|
p += x;
|
|
|
|
const int ia=(int)(alpha*256.0);
|
|
// copy, alpha=1, alpha=0.5, 0.25, 0.75 optimizations
|
|
if ((mode&LICE_BLIT_MODE_MASK)==LICE_BLIT_MODE_COPY)
|
|
{
|
|
if (ia==256)
|
|
{
|
|
_LICE_Template_Blit0<_LICE_CombinePixelsClobberFAST>::solidBlitFAST(p,w,h,color,sp);
|
|
return;
|
|
}
|
|
if (ia==128)
|
|
{
|
|
// we use _LICE_CombinePixelsHalfMix2 because we pre-halve color here
|
|
_LICE_Template_Blit0<_LICE_CombinePixelsHalfMix2FAST>::solidBlitFAST(p,w,h,(color>>1)&0x7f7f7f7f,sp);
|
|
return;
|
|
}
|
|
if (ia==64)
|
|
{
|
|
_LICE_Template_Blit0<_LICE_CombinePixelsQuarterMix2FAST>::solidBlitFAST(p,w,h,(color>>2)&0x3f3f3f3f,sp);
|
|
return;
|
|
}
|
|
if (ia==192)
|
|
{
|
|
_LICE_Template_Blit0<_LICE_CombinePixelsThreeQuarterMix2FAST>::solidBlitFAST(p,w,h,
|
|
((color>>1)&0x7f7f7f7f)+((color>>2)&0x3f3f3f3f),sp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
LICE_COMBINEFUNC blitfunc=NULL;
|
|
#define __LICE__ACTION(comb) blitfunc=comb::doPix;
|
|
#else
|
|
#define __LICE__ACTION(comb) _LICE_Template_Blit1<comb>::solidBlit((LICE_pixel_chan*)p,w,h,LICE_GETR(color),LICE_GETG(color),LICE_GETB(color),LICE_GETA(color),ia,sp*sizeof(LICE_pixel))
|
|
#endif
|
|
|
|
// we use __LICE_ACTION_NOSRCALPHA even though __LICE_ACTION_CONSTANTALPHA
|
|
// is valid, sinc we optimized the 1.0f/0.5f cases above
|
|
__LICE_ACTION_NOSRCALPHA(mode,ia,false);
|
|
#undef __LICE__ACTION
|
|
|
|
#ifdef LICE_FAVOR_SIZE_EXTREME
|
|
if (blitfunc) _LICE_Template_Blit1::solidBlit((LICE_pixel_chan*)p,w,h,LICE_GETR(color),LICE_GETG(color),LICE_GETB(color),LICE_GETA(color),ia,sp*sizeof(LICE_pixel),blitfunc);
|
|
#endif
|
|
}
|
|
|
|
void LICE_ClearRect(LICE_IBitmap *dest, int x, int y, int w, int h, LICE_pixel mask, LICE_pixel orbits)
|
|
{
|
|
if (!dest) return;
|
|
LICE_pixel *p=dest->getBits();
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
DO_RECT_SC(0)
|
|
|
|
if (x<0) { w+=x; x=0; }
|
|
if (y<0) { h+=y; y=0; }
|
|
|
|
const int sp=dest->getRowSpan();
|
|
if (!p || !sp || w<1 || h < 1 || x >= destbm_w || y >= destbm_h) return;
|
|
|
|
if (w>destbm_w-x) w=destbm_w-x;
|
|
if (h>destbm_h-y) h=destbm_h-y;
|
|
|
|
if (dest->isFlipped())
|
|
{
|
|
p+=(destbm_h - y - h)*sp;
|
|
}
|
|
else p+=sp*y;
|
|
|
|
p += x;
|
|
while (h-->0)
|
|
{
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
*p = (*p&mask)|orbits;
|
|
p++;
|
|
}
|
|
p+=sp-w;
|
|
}
|
|
}
|
|
|
|
|
|
LICE_pixel LICE_GetPixel(LICE_IBitmap *bm, int x, int y)
|
|
{
|
|
if (!bm) return 0;
|
|
|
|
int w = bm->getWidth(), h = bm->getHeight();
|
|
const int __sc = (int)bm->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
__LICE_SCU(w);
|
|
__LICE_SCU(h);
|
|
__LICE_SC(x);
|
|
__LICE_SC(y);
|
|
}
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (bm->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_GETPIXEL_ACCEL))
|
|
{
|
|
LICE_Ext_GetPixel_acceldata data(x, y);
|
|
if (bm->Extended(LICE_EXT_GETPIXEL_ACCEL, &data)) return data.px;
|
|
}
|
|
#endif
|
|
|
|
const LICE_pixel *px;
|
|
|
|
if (!(px=bm->getBits()) || x < 0 || y < 0 || x >= w || y>= h) return 0;
|
|
if (bm->isFlipped()) return px[(h-1-y) * bm->getRowSpan() + x];
|
|
return px[y * bm->getRowSpan() + x];
|
|
}
|
|
|
|
void LICE_PutPixel(LICE_IBitmap *bm, int x, int y, LICE_pixel color, float alpha, int mode)
|
|
{
|
|
if (!bm) return;
|
|
|
|
const int __sc = (int)bm->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0)
|
|
{
|
|
if (!IGNORE_SCALING(mode))
|
|
{
|
|
LICE_FillRect(bm,x,y,1,1,color,alpha,mode);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
int w = bm->getWidth(), h = bm->getHeight();
|
|
if (__sc>0)
|
|
{
|
|
__LICE_SCU(w);
|
|
__LICE_SCU(h);
|
|
}
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (bm->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_PUTPIXEL_ACCEL))
|
|
{
|
|
LICE_Ext_PutPixel_acceldata data(x, y, color, alpha, mode);
|
|
if (bm->Extended(LICE_EXT_PUTPIXEL_ACCEL, &data)) return;
|
|
}
|
|
#endif
|
|
|
|
LICE_pixel *px;
|
|
if (!(px=bm->getBits()) || x < 0 || y < 0 || x >= w || y >= h) return;
|
|
|
|
if (bm->isFlipped()) px+=x+(h-1-y)*bm->getRowSpan();
|
|
else px+=x+y*bm->getRowSpan();
|
|
|
|
int ia = (int)(alpha * 256.0f);
|
|
if ((mode&LICE_BLIT_MODE_MASK)==LICE_BLIT_MODE_COPY)
|
|
{
|
|
if (ia==256)
|
|
{
|
|
*px = color;
|
|
return;
|
|
}
|
|
if (ia==128)
|
|
{
|
|
*px = ((*px>>1)&0x7f7f7f7f) + ((color>>1)&0x7f7f7f7f);
|
|
return;
|
|
}
|
|
if (ia==64)
|
|
{
|
|
*px = ((*px>>1)&0x7f7f7f7f) + ((*px>>2)&0x3f3f3f3f) + ((color>>2)&0x3f3f3f3f);
|
|
return;
|
|
}
|
|
if (ia==192)
|
|
{
|
|
*px = ((*px>>2)&0x3f3f3f3f) + ((color>>1)&0x7f7f7f7f) + ((color>>2)&0x3f3f3f3f);
|
|
return;
|
|
}
|
|
}
|
|
#define __LICE__ACTION(comb) comb::doPix((LICE_pixel_chan *)px, LICE_GETR(color),LICE_GETG(color),LICE_GETB(color),LICE_GETA(color), ia)
|
|
__LICE_ACTION_NOSRCALPHA(mode,ia,false);
|
|
#undef __LICE__ACTION
|
|
}
|
|
|
|
|
|
#ifndef LICE_NO_BLIT_SUPPORT
|
|
|
|
template<class T> class LICE_TransformBlit_class
|
|
{
|
|
public:
|
|
static void blit(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
const T *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*2 long, and be in source image coordinates
|
|
float alpha, int mode)
|
|
{
|
|
if (!dest || !src || dstw<1 || dsth<1 || div_w<2 || div_h<2) return;
|
|
|
|
int cypos=dsty;
|
|
double ypos=dsty;
|
|
double dxpos=dstw/(float)(div_w-1);
|
|
double dypos=dsth/(float)(div_h-1);
|
|
int y;
|
|
const T *curpoints=srcpoints;
|
|
for (y = 0; y < div_h-1; y ++)
|
|
{
|
|
int nypos=(int)((ypos+=dypos) + 0.5);
|
|
int x;
|
|
double xpos=dstx;
|
|
int cxpos=dstx;
|
|
|
|
if (nypos != cypos)
|
|
{
|
|
double iy=1.0/(double)(nypos-cypos);
|
|
for (x = 0; x < div_w-1; x ++)
|
|
{
|
|
int nxpos=(int) ((xpos+=dxpos) + 0.5);
|
|
if (nxpos != cxpos)
|
|
{
|
|
int offs=x*2;
|
|
double sx=curpoints[offs];
|
|
double sy=curpoints[offs+1];
|
|
double sw=curpoints[offs+2]-sx;
|
|
double sh=curpoints[offs+3]-sy;
|
|
|
|
offs+=div_w*2;
|
|
double sxdiff=curpoints[offs]-sx;
|
|
double sydiff=curpoints[offs+1]-sy;
|
|
double sw3=curpoints[offs+2]-curpoints[offs];
|
|
double sh3=curpoints[offs+3]-curpoints[offs+1];
|
|
|
|
double ix=1.0/(double)(nxpos-cxpos);
|
|
double dsdx=sw*ix;
|
|
double dtdx=sh*ix;
|
|
double dsdx2=sw3*ix;
|
|
double dtdx2=sh3*ix;
|
|
double dsdy=sxdiff*iy;
|
|
double dtdy=sydiff*iy;
|
|
double dsdxdy = (dsdx2-dsdx)*iy;
|
|
double dtdxdy = (dtdx2-dtdx)*iy;
|
|
|
|
LICE_DeltaBlit(dest,src,cxpos,cypos,nxpos-cxpos,nypos-cypos,
|
|
(float)sx,(float)sy,(float)sw,(float)sh,
|
|
dsdx,dtdx,dsdy,dtdy,dsdxdy,dtdxdy,false,alpha,mode);
|
|
}
|
|
|
|
cxpos=nxpos;
|
|
}
|
|
}
|
|
curpoints+=div_w*2;
|
|
cypos=nypos;
|
|
}
|
|
}
|
|
};
|
|
|
|
template<class T> class LICE_TransformBlitAlpha_class
|
|
{
|
|
public:
|
|
static void blit(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
const T *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*2 long, and be in source image coordinates
|
|
int mode)
|
|
{
|
|
if (!dest || !src || dstw<1 || dsth<1 || div_w<2 || div_h<2) return;
|
|
|
|
int cypos=dsty;
|
|
double ypos=dsty;
|
|
double dxpos=dstw/(float)(div_w-1);
|
|
double dypos=dsth/(float)(div_h-1);
|
|
int y;
|
|
const T *curpoints=srcpoints;
|
|
for (y = 0; y < div_h-1; y ++)
|
|
{
|
|
int nypos=(int)((ypos+=dypos)+0.5);
|
|
int x;
|
|
double xpos=dstx;
|
|
int cxpos=dstx;
|
|
|
|
if (nypos != cypos)
|
|
{
|
|
double iy=1.0/(double)(nypos-cypos);
|
|
for (x = 0; x < div_w-1; x ++)
|
|
{
|
|
int nxpos=(int) ((xpos+=dxpos)+0.5);
|
|
if (nxpos != cxpos)
|
|
{
|
|
int offs=x*3;
|
|
double sx=curpoints[offs];
|
|
double sy=curpoints[offs+1];
|
|
double sa=curpoints[offs+2];
|
|
double sw=curpoints[offs+3]-sx;
|
|
double sh=curpoints[offs+4]-sy;
|
|
double sa2 = curpoints[offs+5]-sa;
|
|
|
|
offs+=div_w*3;
|
|
double sxdiff=curpoints[offs]-sx;
|
|
double sydiff=curpoints[offs+1]-sy;
|
|
double sadiff=curpoints[offs+2]-sa;
|
|
double sw3=curpoints[offs+3]-curpoints[offs];
|
|
double sh3=curpoints[offs+4]-curpoints[offs+1];
|
|
double sa3=curpoints[offs+5]-curpoints[offs+2];
|
|
|
|
double ix=1.0/(double)(nxpos-cxpos);
|
|
double dsdx=sw*ix;
|
|
double dtdx=sh*ix;
|
|
double dadx=sa2*ix;
|
|
double dsdx2=sw3*ix;
|
|
double dtdx2=sh3*ix;
|
|
double dadx2=sa3*ix;
|
|
double dsdy=sxdiff*iy;
|
|
double dtdy=sydiff*iy;
|
|
double dady=sadiff*iy;
|
|
double dsdxdy = (dsdx2-dsdx)*iy;
|
|
double dtdxdy = (dtdx2-dtdx)*iy;
|
|
double dadxdy = (dadx2-dadx)*iy;
|
|
|
|
LICE_DeltaBlitAlpha(dest,src,cxpos,cypos,nxpos-cxpos,nypos-cypos,
|
|
(float)sx,(float)sy,(float)sw,(float)sh,
|
|
dsdx,dtdx,dsdy,dtdy,dsdxdy,dtdxdy,false,sa,mode,dadx,dady,dadxdy);
|
|
}
|
|
|
|
cxpos=nxpos;
|
|
}
|
|
}
|
|
curpoints+=div_w*3;
|
|
cypos=nypos;
|
|
}
|
|
}
|
|
};
|
|
|
|
void LICE_TransformBlit(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
const float *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*2 long, and be in source image coordinates
|
|
float alpha, int mode)
|
|
{
|
|
LICE_TransformBlit_class<float>::blit(dest,src,dstx,dsty,dstw,dsth,srcpoints,div_w,div_h,alpha,mode);
|
|
}
|
|
void LICE_TransformBlit2(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
const double *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*2 long, and be in source image coordinates
|
|
float alpha, int mode)
|
|
{
|
|
LICE_TransformBlit_class<double>::blit(dest,src,dstx,dsty,dstw,dsth,srcpoints,div_w,div_h,alpha,mode);
|
|
}
|
|
|
|
|
|
void LICE_TransformBlit2Alpha(LICE_IBitmap *dest, LICE_IBitmap *src,
|
|
int dstx, int dsty, int dstw, int dsth,
|
|
const double *srcpoints, int div_w, int div_h, // srcpoints coords should be div_w*div_h*3 long, and be in source image coordinates+alpha
|
|
int mode)
|
|
{
|
|
LICE_TransformBlitAlpha_class<double>::blit(dest,src,dstx,dsty,dstw,dsth,srcpoints,div_w,div_h,mode);
|
|
}
|
|
#endif
|
|
|
|
#ifndef LICE_NO_MISC_SUPPORT
|
|
|
|
void LICE_SetAlphaFromColorMask(LICE_IBitmap *dest, LICE_pixel color)
|
|
{
|
|
if (!dest) return;
|
|
LICE_pixel *p=dest->getBits();
|
|
int h=dest->getHeight();
|
|
int w=dest->getWidth();
|
|
int sp=dest->getRowSpan();
|
|
if (!p || w<1 || h<1 || sp<1) return;
|
|
|
|
while (h-->0)
|
|
{
|
|
int n=w;
|
|
while (n--)
|
|
{
|
|
if ((*p&LICE_RGBA(255,255,255,0)) == color) *p&=LICE_RGBA(255,255,255,0);
|
|
else *p|=LICE_RGBA(0,0,0,255);
|
|
p++;
|
|
}
|
|
p+=sp-w;
|
|
}
|
|
}
|
|
|
|
|
|
void LICE_SimpleFill(LICE_IBitmap *dest, int x, int y, LICE_pixel newcolor,
|
|
LICE_pixel comparemask,
|
|
LICE_pixel keepmask)
|
|
{
|
|
if (!dest) return;
|
|
int dw=dest->getWidth();
|
|
int dh=dest->getHeight();
|
|
int rowsize=dest->getRowSpan();
|
|
if (x<0||x>=dw||y<0||y>=dh) return;
|
|
LICE_pixel *ptr=dest->getBits();
|
|
if (!ptr) return;
|
|
ptr += rowsize*y;
|
|
|
|
LICE_pixel compval=ptr[x]&comparemask;
|
|
int ay;
|
|
for (ay=y;ay<dh; ay++)
|
|
{
|
|
if ((ptr[x]&comparemask)!=compval) break;
|
|
ptr[x]=(ptr[x]&keepmask)|newcolor;
|
|
|
|
int ax;
|
|
for(ax=x+1;ax<dw;ax++)
|
|
{
|
|
if ((ptr[ax]&comparemask)!=compval) break;
|
|
ptr[ax]=(ptr[ax]&keepmask)|newcolor;
|
|
}
|
|
ax=x;
|
|
while (--ax>=0)
|
|
{
|
|
if ((ptr[ax]&comparemask)!=compval) break;
|
|
ptr[ax]=(ptr[ax]&keepmask)|newcolor;
|
|
}
|
|
|
|
ptr+=rowsize;
|
|
}
|
|
ptr =dest->getBits()+rowsize*y;
|
|
|
|
ay=y;
|
|
while (--ay>=0)
|
|
{
|
|
ptr-=rowsize;
|
|
if ((ptr[x]&comparemask)!=compval) break;
|
|
ptr[x]=(ptr[x]&keepmask)|newcolor;
|
|
|
|
int ax;
|
|
for(ax=x+1;ax<dw;ax++)
|
|
{
|
|
if ((ptr[ax]&comparemask)!=compval) break;
|
|
ptr[ax]=(ptr[ax]&keepmask)|newcolor;
|
|
}
|
|
ax=x;
|
|
while (--ax>=0)
|
|
{
|
|
if ((ptr[ax]&comparemask)!=compval) break;
|
|
ptr[ax]=(ptr[ax]&keepmask)|newcolor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// VS6 instantiates this wrong as a template function, needs to be a template class
|
|
template <class COMBFUNC> class GlyphDrawImpl
|
|
{
|
|
public:
|
|
static void DrawGlyph(const LICE_pixel_chan* srcalpha, LICE_pixel* destpx, int src_w, int src_h, LICE_pixel color, int span, int src_span, int aa)
|
|
{
|
|
const int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
|
|
|
|
int xi, yi;
|
|
for (yi = 0; yi < src_h; ++yi, srcalpha += src_span, destpx += span) {
|
|
const LICE_pixel_chan* tsrc = srcalpha;
|
|
LICE_pixel* tdest = destpx;
|
|
for (xi = 0; xi < src_w; ++xi, ++tsrc, ++tdest) {
|
|
const LICE_pixel_chan v = *tsrc;
|
|
if (v) { // glyphs should be expected to have a lot of "holes"
|
|
COMBFUNC::doPix((LICE_pixel_chan*) tdest, r, g, b, a, v*aa/256);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static void DrawGlyphScale(const LICE_pixel_chan* srcalpha, LICE_pixel* destpx, int src_w, int src_h, LICE_pixel color, int span, int src_span, int aa, int scale)
|
|
{
|
|
const int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
|
|
|
|
int xi, yi;
|
|
int ysum = 0;
|
|
for (yi = 0; yi < src_h; ++yi, srcalpha += src_span) {
|
|
ysum += scale;
|
|
while (ysum > 255)
|
|
{
|
|
const LICE_pixel_chan* tsrc = srcalpha;
|
|
LICE_pixel* tdest = destpx;
|
|
ysum -= 256;
|
|
destpx += span;
|
|
int sum = 0;
|
|
for (xi = 0; xi < src_w; ++xi, ++tsrc) {
|
|
const LICE_pixel_chan v = *tsrc;
|
|
sum += scale;
|
|
if (v) { // glyphs should be expected to have a lot of "holes"
|
|
while (sum>255)
|
|
{
|
|
COMBFUNC::doPix((LICE_pixel_chan*) tdest, r, g, b, a, v*aa/256);
|
|
tdest++;
|
|
sum -= 256;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tdest += sum/256;
|
|
sum &= 255;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static void DrawGlyphMono(const unsigned char * srcalpha, LICE_pixel* destpx, int src_w, int src_h, LICE_pixel color, int span, int src_span, int aa)
|
|
{
|
|
const int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
|
|
|
|
int xi, yi;
|
|
for (yi = 0; yi < src_h; ++yi, srcalpha += src_span, destpx += span) {
|
|
const unsigned char *tsrc = srcalpha;
|
|
LICE_pixel* tdest = destpx;
|
|
unsigned char cv=0;
|
|
for (xi = 0; xi < src_w; ++xi, ++tdest) {
|
|
if (!(xi&7)) cv = *tsrc++;
|
|
const LICE_pixel_chan v = (cv&128)?255:0;
|
|
cv<<=1;
|
|
if (v) { // glyphs should be expected to have a lot of "holes"
|
|
COMBFUNC::doPix((LICE_pixel_chan*) tdest, r, g, b, a, v*aa/256);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static void DrawGlyphMonoScale(const unsigned char * srcalpha, LICE_pixel* destpx, int src_w, int src_h, LICE_pixel color, int span, int src_span, int aa, int scale)
|
|
{
|
|
const int r = LICE_GETR(color), g = LICE_GETG(color), b = LICE_GETB(color), a = LICE_GETA(color);
|
|
|
|
int xi, yi;
|
|
int ysum=0;
|
|
for (yi = 0; yi < src_h; ++yi, srcalpha += src_span) {
|
|
ysum += scale;
|
|
while (ysum > 255)
|
|
{
|
|
const unsigned char *tsrc = srcalpha;
|
|
LICE_pixel* tdest = destpx;
|
|
unsigned char cv=0;
|
|
int sum=0;
|
|
ysum -= 256;
|
|
destpx++;
|
|
for (xi = 0; xi < src_w; ++xi) {
|
|
if (!(xi&7)) cv = *tsrc++;
|
|
const LICE_pixel_chan v = (cv&128)?255:0;
|
|
cv<<=1;
|
|
sum += scale;
|
|
if (v) { // glyphs should be expected to have a lot of "holes"
|
|
while (sum > 255)
|
|
{
|
|
COMBFUNC::doPix((LICE_pixel_chan*) tdest, r, g, b, a, v*aa/256);
|
|
tdest++;
|
|
sum -= 256;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tdest += sum/256;
|
|
sum &= 255;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void LICE_DrawGlyphEx(LICE_IBitmap* dest, int x, int y, LICE_pixel color, const LICE_pixel_chan* alphas, int glyph_w, int glyph_span, int glyph_h, float alpha, int mode)
|
|
{
|
|
if (!dest) return;
|
|
|
|
#ifndef DISABLE_LICE_EXTENSIONS
|
|
if (dest->Extended(LICE_EXT_SUPPORTS_ID, (void*) LICE_EXT_DRAWGLYPH_ACCEL) && glyph_w == glyph_span)
|
|
{
|
|
LICE_Ext_DrawGlyph_acceldata data(x, y, color, alphas, glyph_w, glyph_h, alpha, mode);
|
|
if (dest->Extended(LICE_EXT_DRAWGLYPH_ACCEL, &data)) return;
|
|
}
|
|
#endif
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0 && IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
}
|
|
|
|
if (glyph_span < 0) alphas += -glyph_span * (glyph_h-1);
|
|
|
|
const int ia= (int)(alpha*256.0f);
|
|
|
|
int src_x = 0, src_y = 0, src_w = glyph_w, src_h = glyph_h;
|
|
if (x <= -src_w || y <= -src_h) return;
|
|
|
|
if (x < 0) {
|
|
src_x -= x;
|
|
if (src_x < 0) return; // overflow
|
|
src_w += x;
|
|
x = 0;
|
|
}
|
|
if (y < 0) {
|
|
src_y -= y;
|
|
if (src_y < 0) return; // overflow
|
|
src_h += y;
|
|
y = 0;
|
|
}
|
|
|
|
if (src_w < 0 || src_h < 0 || x >= destbm_w || y >= destbm_h) return;
|
|
|
|
if (src_h > destbm_h-y) src_h = destbm_h-y;
|
|
if (src_w > destbm_w-x) src_w = destbm_w-x;
|
|
|
|
if (src_w < 1 || src_h < 1) return;
|
|
|
|
if (__sc>0 && !IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
__LICE_SC(x);
|
|
__LICE_SC(y);
|
|
}
|
|
|
|
LICE_pixel* destpx = dest->getBits();
|
|
int span = dest->getRowSpan();
|
|
if (dest->isFlipped()) {
|
|
destpx += (destbm_h-y-1)*span+x;
|
|
span = -span;
|
|
}
|
|
else {
|
|
destpx += y*dest->getRowSpan()+x;
|
|
}
|
|
|
|
const LICE_pixel_chan* srcalpha = alphas+src_y*glyph_span+src_x;
|
|
|
|
if (__sc>0 && !IGNORE_SCALING(mode))
|
|
{
|
|
#define __LICE__ACTION(COMBFUNC) GlyphDrawImpl<COMBFUNC>::DrawGlyphScale(srcalpha,destpx, src_w, src_h, color,span,glyph_span,ia,__sc)
|
|
__LICE_ACTION_NOSRCALPHA(mode, ia, false);
|
|
#undef __LICE__ACTION
|
|
}
|
|
else
|
|
{
|
|
#define __LICE__ACTION(COMBFUNC) GlyphDrawImpl<COMBFUNC>::DrawGlyph(srcalpha,destpx, src_w, src_h, color,span,glyph_span,ia)
|
|
__LICE_ACTION_NOSRCALPHA(mode, ia, false);
|
|
#undef __LICE__ACTION
|
|
}
|
|
}
|
|
|
|
void LICE_DrawGlyph(LICE_IBitmap* dest, int x, int y, LICE_pixel color, const LICE_pixel_chan* alphas, int glyph_w, int glyph_h, float alpha, int mode)
|
|
{
|
|
LICE_DrawGlyphEx(dest,x,y,color,alphas,glyph_w,glyph_w,glyph_h,alpha,mode);
|
|
}
|
|
|
|
|
|
void LICE_DrawMonoGlyph(LICE_IBitmap* dest, int x, int y, LICE_pixel color, const unsigned char *alphabits, int glyph_w, int glyph_span, int glyph_h, float alpha, int mode)
|
|
{
|
|
if (!dest) return;
|
|
|
|
int destbm_w = dest->getWidth(), destbm_h = dest->getHeight();
|
|
const int __sc = (int)dest->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (__sc>0 && IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
}
|
|
|
|
if (glyph_span < 0) alphabits += -glyph_span * (glyph_h-1);
|
|
|
|
const int ia= (int)(alpha*256.0f);
|
|
|
|
int src_x = 0, src_y = 0, src_w = glyph_w, src_h = glyph_h;
|
|
if (x <= -src_w || y <= -src_h) return;
|
|
|
|
if (x < 0) {
|
|
src_x -= x;
|
|
src_w += x;
|
|
x = 0;
|
|
}
|
|
if (y < 0) {
|
|
src_y -= y;
|
|
src_h += y;
|
|
y = 0;
|
|
}
|
|
|
|
if (src_w < 0 || src_h < 0 || x >= destbm_w || y >= destbm_h) return;
|
|
|
|
if (src_h > destbm_h-y) src_h = destbm_h-y;
|
|
if (src_w > destbm_w-x) src_w = destbm_w-x;
|
|
|
|
if (src_w < 1 || src_h < 1) return;
|
|
|
|
if (__sc>0 && !IGNORE_SCALING(mode))
|
|
{
|
|
__LICE_SCU(destbm_w);
|
|
__LICE_SCU(destbm_h);
|
|
__LICE_SC(x);
|
|
__LICE_SC(y);
|
|
}
|
|
|
|
LICE_pixel* destpx = dest->getBits();
|
|
int span = dest->getRowSpan();
|
|
if (dest->isFlipped()) {
|
|
destpx += (destbm_h-y-1)*span+x;
|
|
span = -span;
|
|
}
|
|
else {
|
|
destpx += y*dest->getRowSpan()+x;
|
|
}
|
|
|
|
const unsigned char * srcalpha = alphabits+src_y*glyph_span+src_x;
|
|
if (__sc>0 && !IGNORE_SCALING(mode))
|
|
{
|
|
#define __LICE__ACTION(COMBFUNC) GlyphDrawImpl<COMBFUNC>::DrawGlyphMonoScale(srcalpha,destpx, src_w, src_h, color,span,glyph_span,ia,__sc)
|
|
__LICE_ACTION_NOSRCALPHA(mode, ia, false);
|
|
#undef __LICE__ACTION
|
|
}
|
|
else
|
|
{
|
|
#define __LICE__ACTION(COMBFUNC) GlyphDrawImpl<COMBFUNC>::DrawGlyphMono(srcalpha,destpx, src_w, src_h, color,span,glyph_span,ia)
|
|
__LICE_ACTION_NOSRCALPHA(mode, ia, false);
|
|
#undef __LICE__ACTION
|
|
}
|
|
}
|
|
|
|
void LICE_HalveBlitAA(LICE_IBitmap *dest, LICE_IBitmap *src)
|
|
{
|
|
if (!dest||!src) return;
|
|
int w = dest->getWidth();
|
|
if (w > src->getWidth()/2) w=src->getWidth()/2;
|
|
int h = dest->getHeight();
|
|
if (h > src->getHeight()/2) h=src->getHeight()/2;
|
|
int src_span = src->getRowSpan();
|
|
int dest_span = dest->getRowSpan();
|
|
const LICE_pixel *srcptr = src->getBits();
|
|
LICE_pixel *destptr = dest->getBits();
|
|
|
|
while (h--)
|
|
{
|
|
const LICE_pixel *sp = srcptr;
|
|
const LICE_pixel *sp2 = srcptr+src_span;
|
|
LICE_pixel *dp = destptr;
|
|
int x=w/2;
|
|
|
|
// this is begging for SSE intrinsics, but we never use this function so leave it as-is :)
|
|
|
|
// perhaps we should use more precision rather than chopping each src pixel to 6 bits, but oh well
|
|
while (x--) // unroll 2px at a time, about 5% faster on core2 and ICC
|
|
{
|
|
int r1=((sp[0]>>2)&0x3f3f3f3f);
|
|
int r2=((sp[2]>>2)&0x3f3f3f3f);
|
|
r1 += ((sp[1]>>2)&0x3f3f3f3f);
|
|
r2 += ((sp[3]>>2)&0x3f3f3f3f);
|
|
dp[0] = r1 +
|
|
((sp2[0]>>2)&0x3f3f3f3f) +
|
|
((sp2[1]>>2)&0x3f3f3f3f);
|
|
dp[1] = r2 +
|
|
((sp2[2]>>2)&0x3f3f3f3f) +
|
|
((sp2[3]>>2)&0x3f3f3f3f);
|
|
sp+=4;
|
|
sp2+=4;
|
|
dp+=2;
|
|
}
|
|
if (w&1)
|
|
{
|
|
*dp =
|
|
((sp[0]>>2)&0x3f3f3f3f) +
|
|
((sp[1]>>2)&0x3f3f3f3f) +
|
|
((sp2[0]>>2)&0x3f3f3f3f) +
|
|
((sp2[1]>>2)&0x3f3f3f3f);
|
|
}
|
|
srcptr+=src_span*2;
|
|
destptr+=dest_span;
|
|
}
|
|
}
|
|
|
|
#endif // LICE_NO_MISC_SUPPORT
|
|
|
|
int LICE_BitmapCmp(LICE_IBitmap* a, LICE_IBitmap* b, int *coordsOut)
|
|
{
|
|
return LICE_BitmapCmpEx(a,b,LICE_RGBA(255,255,255,255),coordsOut);
|
|
}
|
|
|
|
int LICE_BitmapCmpEx(LICE_IBitmap* a, LICE_IBitmap* b, LICE_pixel mask, int *coordsOut)
|
|
{
|
|
if (!a || !b) {
|
|
if (!a && b) return -1;
|
|
if (a && !b) return 1;
|
|
return 0;
|
|
}
|
|
|
|
int aw = a->getWidth(), bw = b->getWidth();
|
|
if (aw != bw) return bw-aw;
|
|
int ah = a->getHeight(), bh = b->getHeight();
|
|
if (ah != bh) return bh-ah;
|
|
|
|
//coordsOut
|
|
const LICE_pixel *px1 = a->getBits();
|
|
const LICE_pixel *px2 = b->getBits();
|
|
int span1 = a->getRowSpan();
|
|
int span2 = b->getRowSpan();
|
|
if (a->isFlipped())
|
|
{
|
|
px1+=span1*(ah-1);
|
|
span1=-span1;
|
|
}
|
|
if (b->isFlipped())
|
|
{
|
|
px2+=span2*(ah-1);
|
|
span2=-span2;
|
|
}
|
|
|
|
int y;
|
|
if (!coordsOut)
|
|
{
|
|
if (mask == (LICE_pixel)LICE_RGBA(255,255,255,255))
|
|
for (y=0; y < ah; y ++)
|
|
{
|
|
const int dv = memcmp(px1,px2,aw*sizeof(LICE_pixel));
|
|
if (dv) return dv;
|
|
px1+=span1;
|
|
px2+=span2;
|
|
}
|
|
else
|
|
for (y=0; y < ah; y ++)
|
|
{
|
|
const LICE_pixel *ptr1 = px1, *ptr2 = px2;
|
|
int x=aw;
|
|
while (x--)
|
|
if ((*ptr1++ ^ *ptr2++) & mask) return true;
|
|
px1+=span1;
|
|
px2+=span2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int x;
|
|
|
|
// find first row that differs
|
|
for (y=0; y < ah; y ++)
|
|
{
|
|
// check left side
|
|
for (x=0;x<aw && !((px1[x]^px2[x])&mask);x++);
|
|
if (x < aw) break;
|
|
|
|
px1+=span1;
|
|
px2+=span2;
|
|
}
|
|
if (y>=ah)
|
|
{
|
|
memset(coordsOut,0,4*sizeof(int));
|
|
return 0; // no differences
|
|
}
|
|
|
|
int miny=y;
|
|
int minx=x;
|
|
// scan right edge of top differing row
|
|
for (x=aw-1;x>minx && !((px1[x]^px2[x])&mask);x--);
|
|
int maxx=x;
|
|
|
|
// find last row that differs
|
|
px1+=span1 * (ah-1-y);
|
|
px2+=span2 * (ah-1-y);
|
|
for (y = ah-1; y > miny; y --)
|
|
{
|
|
// check left side
|
|
for (x=0;x<aw && !((px1[x]^px2[x])&mask);x++);
|
|
if (x < aw)
|
|
{
|
|
if (x < minx) minx=x;
|
|
break;
|
|
}
|
|
px1-=span1;
|
|
px2-=span2;
|
|
}
|
|
int maxy=y;
|
|
|
|
if (y > miny)
|
|
{
|
|
// scan right edge of bottom row that differs
|
|
for (x=aw-1;x>maxx && !((px1[x]^px2[x])&mask);x--);
|
|
maxx=x;
|
|
}
|
|
|
|
|
|
// find min/max x that differ
|
|
px1+=span1 * (miny+1-y);
|
|
px2+=span2 * (miny+1-y);
|
|
for (y=miny+1;y<maxy && (minx>0 || maxx<aw-1);y++)
|
|
{
|
|
for (x=0;x<minx && !((px1[x]^px2[x])&mask);x++);
|
|
minx=x;
|
|
for (x=aw-1;x>maxx && !((px1[x]^px2[x])&mask);x--);
|
|
maxx=x;
|
|
|
|
px1+=span1;
|
|
px2+=span2;
|
|
}
|
|
|
|
coordsOut[0]=minx;
|
|
coordsOut[1]=miny;
|
|
coordsOut[2]=maxx-minx+1;
|
|
coordsOut[3]=maxy-miny+1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned short _LICE_RGB2HSV_invtab[256]={ // 65536/idx - 1
|
|
0, 0xffff, 0x7fff, 0x5554, 0x3fff, 0x3332, 0x2aa9, 0x2491,
|
|
0x1fff, 0x1c70, 0x1998, 0x1744, 0x1554, 0x13b0, 0x1248, 0x1110,
|
|
0x0fff, 0x0f0e, 0x0e37, 0x0d78, 0x0ccb, 0x0c2f, 0x0ba1, 0x0b20,
|
|
0x0aa9, 0x0a3c, 0x09d7, 0x097a, 0x0923, 0x08d2, 0x0887, 0x0841,
|
|
0x07ff, 0x07c0, 0x0786, 0x074f, 0x071b, 0x06ea, 0x06bb, 0x068f,
|
|
0x0665, 0x063d, 0x0617, 0x05f3, 0x05d0, 0x05af, 0x058f, 0x0571,
|
|
0x0554, 0x0538, 0x051d, 0x0504, 0x04eb, 0x04d3, 0x04bc, 0x04a6,
|
|
0x0491, 0x047c, 0x0468, 0x0455, 0x0443, 0x0431, 0x0420, 0x040f,
|
|
0x03ff, 0x03ef, 0x03df, 0x03d1, 0x03c2, 0x03b4, 0x03a7, 0x039a,
|
|
0x038d, 0x0380, 0x0374, 0x0368, 0x035d, 0x0352, 0x0347, 0x033c,
|
|
0x0332, 0x0328, 0x031e, 0x0314, 0x030b, 0x0302, 0x02f9, 0x02f0,
|
|
0x02e7, 0x02df, 0x02d7, 0x02cf, 0x02c7, 0x02bf, 0x02b8, 0x02b0,
|
|
0x02a9, 0x02a2, 0x029b, 0x0294, 0x028e, 0x0287, 0x0281, 0x027b,
|
|
0x0275, 0x026f, 0x0269, 0x0263, 0x025d, 0x0258, 0x0252, 0x024d,
|
|
0x0248, 0x0242, 0x023d, 0x0238, 0x0233, 0x022f, 0x022a, 0x0225,
|
|
0x0221, 0x021c, 0x0218, 0x0213, 0x020f, 0x020b, 0x0207, 0x0203,
|
|
0x01ff, 0x01fb, 0x01f7, 0x01f3, 0x01ef, 0x01eb, 0x01e8, 0x01e4,
|
|
0x01e0, 0x01dd, 0x01d9, 0x01d6, 0x01d3, 0x01cf, 0x01cc, 0x01c9,
|
|
0x01c6, 0x01c2, 0x01bf, 0x01bc, 0x01b9, 0x01b6, 0x01b3, 0x01b1,
|
|
0x01ae, 0x01ab, 0x01a8, 0x01a5, 0x01a3, 0x01a0, 0x019d, 0x019b,
|
|
0x0198, 0x0196, 0x0193, 0x0191, 0x018e, 0x018c, 0x0189, 0x0187,
|
|
0x0185, 0x0182, 0x0180, 0x017e, 0x017c, 0x0179, 0x0177, 0x0175,
|
|
0x0173, 0x0171, 0x016f, 0x016d, 0x016b, 0x0169, 0x0167, 0x0165,
|
|
0x0163, 0x0161, 0x015f, 0x015d, 0x015b, 0x0159, 0x0157, 0x0156,
|
|
0x0154, 0x0152, 0x0150, 0x014f, 0x014d, 0x014b, 0x0149, 0x0148,
|
|
0x0146, 0x0145, 0x0143, 0x0141, 0x0140, 0x013e, 0x013d, 0x013b,
|
|
0x013a, 0x0138, 0x0137, 0x0135, 0x0134, 0x0132, 0x0131, 0x012f,
|
|
0x012e, 0x012d, 0x012b, 0x012a, 0x0128, 0x0127, 0x0126, 0x0124,
|
|
0x0123, 0x0122, 0x0120, 0x011f, 0x011e, 0x011d, 0x011b, 0x011a,
|
|
0x0119, 0x0118, 0x0117, 0x0115, 0x0114, 0x0113, 0x0112, 0x0111,
|
|
0x0110, 0x010e, 0x010d, 0x010c, 0x010b, 0x010a, 0x0109, 0x0108,
|
|
0x0107, 0x0106, 0x0105, 0x0104, 0x0103, 0x0102, 0x0101, 0x0100,
|
|
};
|
|
|
|
|
|
#endif//__LICE_CPP_IMPLEMENTED__
|