#include <lib/gdi/gpixmap.h>
+#include <lib/gdi/region.h>
+#include <lib/gdi/accel.h>
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);
}
{
if (lookup)
{
- delete lookup;
+ delete [] lookup;
lookup=0;
size=0;
}
}
}
-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(); y<area.bottom(); y++)
- memset(((__u8*)data)+y*stride+area.left(), color.color, area.width());
- else if (bpp == 32)
- for (int y=area.top(); y<area.bottom(); y++)
+ 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;
+
+ data = 0;
+ data_phys = 0;
+
+ if (accel)
+ {
+ stride += 63;
+ stride &=~63;
+
+ if (gAccel::getInstance())
+ eDebug("accel memory: %d", gAccel::getInstance()->accelAlloc(data, data_phys, y * stride));
+ else
+ eDebug("no accel available");
+ }
+
+ clut.colors = 0;
+ clut.data = 0;
+
+ if (!data)
+ data = malloc(y * stride);
+
+ type = 1;
+}
+
+gSurface::~gSurface()
+{
+ if (type)
+ {
+ if (data_phys)
+ gAccel::getInstance()->accelFree(data_phys);
+ else
+ free(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; i<region.rects.size(); ++i)
+ {
+ const eRect &area = region.rects[i];
+ if ((area.height()<=0) || (area.width()<=0))
+ continue;
+
+ if (surface->bpp == 8)
+ {
+ for (int y=area.top(); y<area.bottom(); y++)
+ memset(((__u8*)surface->data)+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);
+
+ if (surface->data_phys && gAccel::getInstance())
+ if (!gAccel::getInstance()->fill(surface, area, col))
+ continue;
+
+ for (int y=area.top(); y<area.bottom(); y++)
+ {
+ __u32 *dst=(__u32*)(((__u8*)surface->data)+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::blit(const gPixmap &src, ePoint pos, const eRect &clip, int flag)
+void gPixmap::blit(const gPixmap &src, ePoint pos, const gRegion &clip, int flag)
{
-
- 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;
-
- eRect srcarea=area;
- srcarea.moveBy(-pos.x(), -pos.y());
-
- if ((bpp == 8) && (src.bpp==8))
+ for (unsigned int i=0; i<clip.rects.size(); ++i)
{
- __u8 *srcptr=(__u8*)src.data;
- __u8 *dstptr=(__u8*)data;
-
- srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
- dstptr+=area.left()*bypp+area.top()*stride;
- for (int y=0; y<area.height(); y++)
+ eRect area=eRect(pos, src.size());
+ area&=clip.rects[i];
+ area&=eRect(ePoint(0, 0), size());
+ if ((area.width()<0) || (area.height()<0))
+ continue;
+
+ eRect srcarea=area;
+ srcarea.moveBy(-pos.x(), -pos.y());
+
+ if ((surface->data_phys && src.surface->data_phys) && (gAccel::getInstance()))
+ if (!gAccel::getInstance()->blit(surface, src.surface, area.topLeft(), srcarea, flag))
+ continue;
+ flag &= ~ blitAlphaBlend;
+
+ if ((surface->bpp == 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; y<area.height(); y++)
{
- // no real alphatest yet
- int width=area.width();
- unsigned char *src=(unsigned char*)srcptr;
- unsigned char *dst=(unsigned char*)dstptr;
- // use duff's device here!
- while (width--)
+ if (flag & blitAlphaTest)
{
- if (!*src)
+ // no real alphatest yet
+ int width=area.width();
+ unsigned char *src=(unsigned char*)srcptr;
+ unsigned char *dst=(unsigned char*)dstptr;
+ // use duff's device here!
+ while (width--)
{
- src++;
- dst++;
- } else
- *dst++=*src++;
- }
- } else
- memcpy(dstptr, srcptr, area.width()*bypp);
- srcptr+=src.stride;
- dstptr+=stride;
- }
- } else if ((bpp == 32) && (src.bpp==8))
- {
- __u8 *srcptr=(__u8*)src.data;
- __u8 *dstptr=(__u8*)data; // !!
- __u32 pal[256];
-
- for (int i=0; i<256; ++i)
+ if (!*src)
+ {
+ src++;
+ dst++;
+ } else
+ *dst++=*src++;
+ }
+ } else
+ memcpy(dstptr, srcptr, area.width()*surface->bypp);
+ srcptr+=src.surface->stride;
+ dstptr+=surface->stride;
+ }
+ } else if ((surface->bpp == 32) && (src.surface->bpp==32))
{
- if (src.clut.data && (i<src.clut.colors))
- pal[i]=(src.clut.data[i].a<<24)|(src.clut.data[i].r<<16)|(src.clut.data[i].g<<8)|(src.clut.data[i].b);
- else
- pal[i]=0x010101*i;
- pal[i]^=0xFF000000;
- }
+ __u32 *srcptr=(__u32*)src.surface->data;
+ __u32 *dstptr=(__u32*)surface->data;
- srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
- dstptr+=area.left()*bypp+area.top()*stride;
- for (int y=0; y<area.height(); y++)
- {
- if (flag & blitAlphaTest)
+ srcptr+=srcarea.left()+srcarea.top()*src.surface->stride/4;
+ dstptr+=area.left()+area.top()*surface->stride/4;
+ for (int y=0; y<area.height(); y++)
{
- // no real alphatest yet
- int width=area.width();
- unsigned char *src=(unsigned char*)srcptr;
- __u32 *dst=(__u32*)dstptr;
- // use duff's device here!
- while (width--)
+ if (flag & blitAlphaTest)
{
- if (!*src)
+ int width=area.width();
+ unsigned long *src=(unsigned long*)srcptr;
+ unsigned long *dst=(unsigned long*)dstptr;
+
+ while (width--)
+ {
+ if (!((*src)&0xFF000000))
+ {
+ src++;
+ dst++;
+ } else
+ *dst++=*src++;
+ }
+ } else if (flag & blitAlphaBlend)
+ {
+ // uh oh. this is only until hardware accel is working.
+
+ int width=area.width();
+ // ARGB color space!
+ unsigned char *src=(unsigned char*)srcptr;
+ unsigned char *dst=(unsigned char*)dstptr;
+
+#define BLEND(x, y, a) (y + ((x-y) * a)/256)
+ while (width--)
+ {
+ unsigned char sa = src[3];
+ unsigned char sr = src[2];
+ unsigned char sg = src[1];
+ unsigned char sb = src[0];
+
+ unsigned char da = dst[3];
+ unsigned char dr = dst[2];
+ unsigned char dg = dst[1];
+ unsigned char db = dst[0];
+
+ dst[3] = BLEND(0xFF, da, sa);
+ dst[2] = BLEND(sr, dr, sa);
+ dst[1] = BLEND(sg, dg, sa);
+ dst[0] = BLEND(sb, db, sa);
+
+ src += 4; dst += 4;
+ }
+ } else
+ memcpy(dstptr, srcptr, area.width()*surface->bypp);
+ 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 && (i<src.surface->clut.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; y<area.height(); y++)
+ {
+ if (flag & blitAlphaTest)
+ {
+ // no real alphatest yet
+ int width=area.width();
+ unsigned char *src=(unsigned char*)srcptr;
+ __u32 *dst=(__u32*)dstptr;
+ // use duff's device here!
+ while (width--)
{
- src++;
- dst++;
- } else
+ if (!*src)
+ {
+ src++;
+ dst++;
+ } else
+ *dst++=pal[*src++];
+ }
+ } else
+ {
+ int width=area.width();
+ unsigned char *src=(unsigned char*)srcptr;
+ __u32 *dst=(__u32*)dstptr;
+ while (width--)
*dst++=pal[*src++];
}
- } else
- {
- int width=area.width();
- unsigned char *src=(unsigned char*)srcptr;
- __u32 *dst=(__u32*)dstptr;
- while (width--)
- *dst++=pal[*src++];
+ srcptr+=src.surface->stride;
+ dstptr+=surface->stride;
}
- srcptr+=src.stride;
- dstptr+=stride;
- }
- } else
- eFatal("cannot blit %dbpp from %dbpp", bpp, src.bpp);
+ } else
+ eFatal("cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp);
+ }
}
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; i<clut.colors; i++)
- lookup[i].color=target.clut.findColor(clut.data[i]);
+ gColor *lookup=new gColor[surface->clut.colors];
+
+ for (int i=0; i<surface->clut.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; ay<y; ay++)
+ for (int ay=0; ay<surface->y; ay++)
{
- for (int ax=0; ax<x; ax++)
+ for (int ax=0; ax<surface->x; ax++)
dstptr[ax]=lookup[dstptr[ax]];
- dstptr+=stride;
+ dstptr+=surface->stride;
}
- delete lookup;
+ delete [] lookup;
}
-void gPixmap::line(ePoint start, ePoint dst, gColor color)
+static inline int sgn(int a)
{
-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.
+ if (a < 0)
+ return -1;
+ else if (!a)
+ return 0;
+ else
+ return 1;
+}
+
+void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color)
+{
+ __u8 *srf8 = 0;
+ __u32 *srf32 = 0;
+ int stride = surface->stride;
+
+ if (clip.rects.empty())
+ return;
+
+ __u32 col;
+ 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 (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<colors; t++)
{
ttd+=td;
if (ttd>=difference)
continue;
+ if (!ttd)
+ return t;
difference=ttd;
best_choice=t;
}
return best_choice;
}
-gPixmap::gPixmap()
-{
-}
+DEFINE_REF(gPixmap);
gPixmap::~gPixmap()
{
}
-gImage::gImage(eSize size, int _bpp)
+gPixmap::gPixmap(gSurface *surface): surface(surface)
{
- 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)
{
- delete[] clut.data;
- delete[] (char*)data;
+ surface = new gSurface(size, bpp, accel);
}
+