/* 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 #include // 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 _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 #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 #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= 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> 16; const LICE_pixel_chan *pin = inptr + offs*sizeof(LICE_pixel); if (offs> 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 #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> 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 #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>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::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::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;y1.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::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::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::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::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::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::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 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 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::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::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::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=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=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 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::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::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::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::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=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 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;y0 || maxxmaxx && !((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__