X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5..3a044bea307a02147e2d01ad29f07b7348bd7203:/lib/gdi/gpixmap.cpp diff --git a/lib/gdi/gpixmap.cpp b/lib/gdi/gpixmap.cpp index c089051d..3e643108 100644 --- a/lib/gdi/gpixmap.cpp +++ b/lib/gdi/gpixmap.cpp @@ -1,15 +1,17 @@ +#include +#include #include +#include +#include gLookup::gLookup() + :size(0), lookup(0) { - size=0; - lookup=0; } gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end) + :size(0), lookup(0) { - size=0; - lookup=0; build(size, pal, start, end); } @@ -17,7 +19,7 @@ void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRG { if (lookup) { - delete lookup; + delete [] lookup; lookup=0; size=0; } @@ -49,177 +51,544 @@ void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRG } } -DEFINE_REF(gPixmap); +gSurface::gSurface() +{ + x = 0; + y = 0; + bpp = 0; + bypp = 0; + stride = 0; + data = 0; + data_phys = 0; + clut.colors = 0; + clut.data = 0; + type = 0; +} -void gPixmap::fill(const eRect &area, const gColor &color) +gSurface::gSurface(eSize size, int _bpp, int accel) { - if ((area.height()<=0) || (area.width()<=0)) - return; - if (bpp == 8) - for (int y=area.top(); yaccelAlloc(data, data_phys, y * stride + pal_size)); + else + eDebug("no accel available"); + } + + clut.colors = 0; + clut.data = 0; + + if (!data) + data = new unsigned char [y * stride]; + + type = 1; +} + +gSurface::~gSurface() +{ + if (type) + { + if (data_phys) + gAccel::getInstance()->accelFree(data_phys); + else + delete [] (unsigned char*)data; + + delete [] clut.data; + } +} + +gPixmap *gPixmap::lock() +{ + contentlock.lock(1); + return this; +} + +void gPixmap::unlock() +{ + contentlock.unlock(1); +} + +void gPixmap::fill(const gRegion ®ion, const gColor &color) +{ + unsigned int i; + for (i=0; ibpp == 8) + { + for (int y=area.top(); ydata)+y*surface->stride+area.left(), color.color, area.width()); + } else if (surface->bpp == 32) { - __u32 *dst=(__u32*)(((__u8*)data)+y*stride+area.left()*bypp); - int x=area.width(); __u32 col; - if (clut.data && color < clut.colors) - col=(clut.data[color].a<<24)|(clut.data[color].r<<16)|(clut.data[color].g<<8)|(clut.data[color].b); + if (surface->clut.data && color < surface->clut.colors) + col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b); else col=0x10101*color; - col^=0xFF000000; - while (x--) - *dst++=col; - } - else - eWarning("couldn't fill %d bpp", bpp); + + col^=0xFF000000; + + if (surface->data_phys && gAccel::getInstance()) + if (!gAccel::getInstance()->fill(surface, area, col)) + continue; + + for (int y=area.top(); ydata)+y*surface->stride+area.left()*surface->bypp); + int x=area.width(); + while (x--) + *dst++=col; + } + } else + eWarning("couldn't fill %d bpp", surface->bpp); + } +} + +void gPixmap::fill(const gRegion ®ion, const gRGB &color) +{ + unsigned int i; + for (i=0; ibpp == 32) + { + __u32 col; + + col = color.argb(); + col^=0xFF000000; + + if (surface->data_phys && gAccel::getInstance()) + if (!gAccel::getInstance()->fill(surface, area, col)) + continue; + + for (int y=area.top(); ydata)+y*surface->stride+area.left()*surface->bypp); + int x=area.width(); + while (x--) + *dst++=col; + } + } else + eWarning("couldn't rgbfill %d bpp", surface->bpp); + } +} + +static void blit_8i_to_32(__u32 *dst, __u8 *src, __u32 *pal, int width) +{ + while (width--) + *dst++=pal[*src++]; +} + +static void blit_8i_to_32_at(__u32 *dst, __u8 *src, __u32 *pal, int width) +{ + while (width--) + { + if (!(pal[*src]&0x80000000)) + { + src++; + dst++; + } else + *dst++=pal[*src++]; + } } -void gPixmap::blit(const gPixmap &src, ePoint pos, const eRect &clip, int flag) + /* WARNING, this function is not endian safe! */ +static void blit_8i_to_32_ab(__u32 *dst, __u8 *src, __u32 *pal, int width) { + while (width--) + { +#define BLEND(x, y, a) (y + (((x-y) * a)>>8)) + __u32 srccol = pal[*src++]; + __u32 dstcol = *dst; + unsigned char sb = srccol & 0xFF; + unsigned char sg = (srccol >> 8) & 0xFF; + unsigned char sr = (srccol >> 16) & 0xFF; + unsigned char sa = (srccol >> 24) & 0xFF; + + unsigned char db = dstcol & 0xFF; + unsigned char dg = (dstcol >> 8) & 0xFF; + unsigned char dr = (dstcol >> 16) & 0xFF; + unsigned char da = (dstcol >> 24) & 0xFF; + + da = BLEND(0xFF, da, sa) & 0xFF; + dr = BLEND(sr, dr, sa) & 0xFF; + dg = BLEND(sg, dg, sa) & 0xFF; + db = BLEND(sb, db, sa) & 0xFF; + +#undef BLEND + *dst++ = db | (dg << 8) | (dr << 16) | (da << 24); + } +} + +#define FIX 0x10000 + +void gPixmap::blit(const gPixmap &src, const eRect &_pos, const gRegion &clip, int flag) +{ +// eDebug("blit: -> %d.%d %d:%d -> %d.%d %d:%d, flags=%d", +// _pos.x(), _pos.y(), _pos.width(), _pos.height(), +// clip.extends.x(), clip.extends.y(), clip.extends.width(), clip.extends.height(), +// flag); + eRect pos = _pos; - eRect area=eRect(pos, src.getSize()); - if (!clip.isNull()) - area&=clip; - area&=eRect(ePoint(0, 0), getSize()); - if ((area.width()<0) || (area.height()<0)) - return; +// eDebug("source size: %d %d", src.size().width(), src.size().height()); - eRect srcarea=area; - srcarea.moveBy(-pos.x(), -pos.y()); + if (!(flag & blitScale)) /* pos' size is valid only when scaling */ + pos = eRect(pos.topLeft(), src.size()); + else if (pos.size() == src.size()) /* no scaling required */ + flag &= ~blitScale; - if ((bpp == 8) && (src.bpp==8)) + int scale_x = FIX, scale_y = FIX; + + if (flag & blitScale) { - __u8 *srcptr=(__u8*)src.data; - __u8 *dstptr=(__u8*)data; + ASSERT(src.size().width()); + ASSERT(src.size().height()); + scale_x = pos.size().width() * FIX / src.size().width(); + scale_y = pos.size().height() * FIX / src.size().height(); + } - srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride; - dstptr+=area.left()*bypp+area.top()*stride; - for (int y=0; ydata_phys && src.surface->data_phys) && (gAccel::getInstance())) + if (!gAccel::getInstance()->blit(surface, src.surface, area, srcarea, flag)) + continue; + + if (flag & blitScale) { - if (src.clut.data && (ibpp == 8) && (src.surface->bpp==8)) { - if (flag & blitAlphaTest) + __u8 *srcptr=(__u8*)src.surface->data; + __u8 *dstptr=(__u8*)surface->data; + + srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride; + dstptr+=area.left()*surface->bypp+area.top()*surface->stride; + for (int y=0; ybypp); + srcptr+=src.surface->stride; + dstptr+=surface->stride; + } + } else if ((surface->bpp == 32) && (src.surface->bpp==32)) + { + __u32 *srcptr=(__u32*)src.surface->data; + __u32 *dstptr=(__u32*)surface->data; + + srcptr+=srcarea.left()+srcarea.top()*src.surface->stride/4; + dstptr+=area.left()+area.top()*surface->stride/4; + for (int y=0; ybypp); + srcptr+=src.surface->stride/4; + dstptr+=surface->stride/4; + } + } else if ((surface->bpp == 32) && (src.surface->bpp==8)) + { + __u8 *srcptr=(__u8*)src.surface->data; + __u8 *dstptr=(__u8*)surface->data; // !! + __u32 pal[256]; + + for (int i=0; i<256; ++i) + { + if (src.surface->clut.data && (iclut.colors)) + pal[i]=(src.surface->clut.data[i].a<<24)|(src.surface->clut.data[i].r<<16)|(src.surface->clut.data[i].g<<8)|(src.surface->clut.data[i].b); + else + pal[i]=0x010101*i; + pal[i]^=0xFF000000; + } + + srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride; + dstptr+=area.left()*surface->bypp+area.top()*surface->stride; + for (int y=0; ystride; + dstptr+=surface->stride; } - srcptr+=src.stride; - dstptr+=stride; - } - } else - eFatal("cannot blit %dbpp from %dbpp", bpp, src.bpp); + } else + eWarning("cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp); + } } +#undef FIX + void gPixmap::mergePalette(const gPixmap &target) { - if ((!clut.colors) || (!target.clut.colors)) + if ((!surface->clut.colors) || (!target.surface->clut.colors)) return; - gColor *lookup=new gColor[clut.colors]; - for (int i=0; iclut.colors]; + + for (int i=0; iclut.colors; i++) + lookup[i].color=target.surface->clut.findColor(surface->clut.data[i]); - delete clut.data; - clut.colors=target.clut.colors; - clut.data=new gRGB[clut.colors]; - memcpy(clut.data, target.clut.data, sizeof(gRGB)*clut.colors); + delete [] surface->clut.data; + surface->clut.colors=target.surface->clut.colors; + surface->clut.data=new gRGB[surface->clut.colors]; + memcpy(surface->clut.data, target.surface->clut.data, sizeof(gRGB)*surface->clut.colors); - __u8 *dstptr=(__u8*)data; + __u8 *dstptr=(__u8*)surface->data; - for (int ay=0; ayy; ay++) { - for (int ax=0; axx; ax++) dstptr[ax]=lookup[dstptr[ax]]; - dstptr+=stride; + dstptr+=surface->stride; } - delete lookup; + delete [] lookup; +} + +static inline int sgn(int a) +{ + if (a < 0) + return -1; + else if (!a) + return 0; + else + return 1; } -void gPixmap::line(ePoint start, ePoint dst, gColor color) +void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color) { -int Ax=start.x(), // dieser code rult ganz ganz doll weil er ganz ganz fast ist und auch sehr gut dokumentiert is -Ay=start.y(), Bx=dst.x(), // t. es handelt sich immerhin um den weltbekannten bresenham algorithmus der nicht nur -By=dst.y(); int dX, dY, fbXincr, // sehr schnell ist sondern auch sehr gut dokumentiert und getestet wurde. nicht -fbYincr, fbXYincr, dPr, dPru, P; __u8 // nur auf dem LCD der dbox, sondern auch ueberall anders. und auch auf der -*AfbAddr = &((__u8*)data)[Ay*stride+Ax*bypp]; __u8 // dbox mit LCD soll das teil nun tun, und ich denke das tut es. ausse -*BfbAddr = &((__u8*)data)[By*stride+Bx*bypp]; fbXincr= // rdem hat dieser algo den vorteil dass man fehler sehr leicht fi -bypp; if ( (dX=Bx-Ax) >= 0) goto AFTERNEGX; dX=-dX; // ndet und beheben kann. das liegt nicht zuletzt an den komment -fbXincr=-1; AFTERNEGX: fbYincr=stride; if ( (dY=By // aren. und ausserdem, je kuerzer der code, desto weniger k --Ay) >= 0) goto AFTERNEGY; fbYincr=-stride; dY=-dY;AFTERNEGY: // ann daran falsch sein. erwaehnte ich schon, da -fbXYincr = fbXincr+fbYincr; if (dY > dX) goto YisIndependent; dPr = dY+ // s dieser tolle code wahnsinnig schnell -dY; P = -dX; dPru = P+P; dY = dX>>1; XLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) // ist? bye, tmbinc -goto RightAndUp; AfbAddr+=fbXincr; BfbAddr-=fbXincr; if ((dY=dY-1) > 0) goto XLOOP; *AfbAddr=color; if ((dX & 1) -== 0) return; *BfbAddr=color; return; RightAndUp: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dY=dY-1) > -0) goto XLOOP; *AfbAddr=color; if ((dX & 1) == 0) return; *BfbAddr=color; return; YisIndependent: dPr = dX+dX; P -= -dY; dPru = P+P; dX = dY>>1; YLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) goto RightAndUp2; AfbAddr -+=fbYincr; BfbAddr-=fbYincr; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr=color; if ((dY & 1) == 0) return; *BfbAddr= -color;return; RightAndUp2: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr -=color; if((dY & 1) == 0) return; *BfbAddr=color; return; // nun ist der tolle code leider zu ende. tut mir leid. + __u8 *srf8 = 0; + __u32 *srf32 = 0; + int stride = surface->stride; + + if (clip.rects.empty()) + return; + + __u32 col = 0; + if (surface->bpp == 8) + { + srf8 = (__u8*)surface->data; + } else if (surface->bpp == 32) + { + srf32 = (__u32*)surface->data; + + if (surface->clut.data && color < surface->clut.colors) + col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b); + else + col=0x10101*color; + col^=0xFF000000; + } + + int xa = start.x(), ya = start.y(), xb = dst.x(), yb = dst.y(); + int dx, dy, x, y, s1, s2, e, temp, swap, i; + dy=abs(yb-ya); + dx=abs(xb-xa); + s1=sgn(xb-xa); + s2=sgn(yb-ya); + x=xa; + y=ya; + if (dy>dx) + { + temp=dx; + dx=dy; + dy=temp; + swap=1; + } else + swap=0; + e = 2*dy-dx; + + int lasthit = 0; + for(i=1; i<=dx; i++) + { + /* i don't like this clipping loop, but the only */ + /* other choice i see is to calculate the intersections */ + /* before iterating through the pixels. */ + + /* one could optimize this because of the ordering */ + /* of the bands. */ + + lasthit = 0; + int a = lasthit; + + /* if last pixel was invisble, first check bounding box */ + if (a == -1) + { + /* check if we just got into the bbox again */ + if (clip.extends.contains(x, y)) + lasthit = a = 0; + else + goto fail; + } else if (!clip.rects[a].contains(x, y)) + { + do + { + ++a; + if ((unsigned int)a == clip.rects.size()) + a = 0; + if (a == lasthit) + { + goto fail; + lasthit = -1; + } + } while (!clip.rects[a].contains(x, y)); + lasthit = a; + } + + if (srf8) + srf8[y * stride + x] = color; + if (srf32) + srf32[y * stride/4 + x] = col; +fail: + while (e>=0) + { + if (swap==1) x+=s1; + else y+=s2; + e-=2*dx; + } + if (swap==1) + y+=s2; + else + x+=s1; + e+=2*dy; + } } gColor gPalette::findColor(const gRGB &rgb) const { + /* grayscale? */ + if (!data) + return (rgb.r + rgb.g + rgb.b) / 3; + int difference=1<<30, best_choice=0; for (int t=0; t=difference) continue; + if (!ttd) + return t; difference=ttd; best_choice=t; } return best_choice; } -gPixmap::gPixmap() -{ -} +DEFINE_REF(gPixmap); gPixmap::~gPixmap() { + if (must_delete_surface) + delete surface; } -gImage::gImage(eSize size, int _bpp) +gPixmap::gPixmap(gSurface *surface) + :surface(surface), must_delete_surface(false) { - x=size.width(); - y=size.height(); - bpp=_bpp; - switch (bpp) - { - case 8: - bypp=1; - break; - case 15: - case 16: - bypp=2; - break; - case 24: // never use 24bit mode - case 32: - bypp=4; - break; - default: - bypp=(bpp+7)/8; - } - stride=x*bypp; - if (bpp==8) - { - clut.colors=256; - clut.data=new gRGB[clut.colors]; - } else - { - clut.colors=0; - clut.data=0; - } - data=new char[x*y*bypp]; } -gImage::~gImage() +gPixmap::gPixmap(eSize size, int bpp, int accel) + :must_delete_surface(true) { - delete[] clut.data; - delete[] (char*)data; + surface = new gSurface(size, bpp, accel); } +