Revert "lib/gdi/font.cpp: call libfribidi for single lines on multi line texts to...
[enigma2.git] / lib / gdi / gpixmap.cpp
index e8ddcf738941b460406dac06854d83add9257d0b..3e64310865ff2683340ff0584607ef9caa8a0ddd 100644 (file)
@@ -1,15 +1,17 @@
+#include <cstdlib>
+#include <cstring>
 #include <lib/gdi/gpixmap.h>
 #include <lib/gdi/gpixmap.h>
+#include <lib/gdi/region.h>
+#include <lib/gdi/accel.h>
 
 gLookup::gLookup()
 
 gLookup::gLookup()
+       :size(0), lookup(0)
 {
 {
-       size=0;
-       lookup=0;
 }
 
 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
 }
 
 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);
 }
 
        build(size, pal, start, end);
 }
 
@@ -17,7 +19,7 @@ void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRG
 {
        if (lookup)
        {
 {
        if (lookup)
        {
-               delete lookup;
+               delete [] lookup;
                lookup=0;
                size=0;
        }
                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(); 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;
+               
+               int pal_size = 0;
+               if (bpp == 8)
+                       pal_size = 256 * 4;
+               
+               if (gAccel::getInstance())
+                       eDebug("accel memory: %d", gAccel::getInstance()->accelAlloc(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 &region, const gColor &color)
+{
+       unsigned int i;
+       for (i=0; i<region.rects.size(); ++i)
+       {
+               const eRect &area = region.rects[i];
+               if (area.empty())
+                       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;
 
                        __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;
                        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(); 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::fill(const gRegion &region, const gRGB &color)
+{
+       unsigned int i;
+       for (i=0; i<region.rects.size(); ++i)
+       {
+               const eRect &area = region.rects[i];
+               if (area.empty())
+                       continue;
+
+               if (surface->bpp == 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(); 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 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; y<area.height(); y++)
-               {
-                       if (flag & blitAlphaTest)
-                       {
-             // 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 (!*src)
-                                       {
-                                               src++;
-                                               dst++;
-                                       } else
-                                               *dst++=*src++;
-                               }
-                       } else
-                               memcpy(dstptr, srcptr, area.width()*bypp);
-                       srcptr+=src.stride;
-                       dstptr+=stride;
-               }
-       } else if ((bpp == 32) && (src.bpp==8))
+//     eDebug("SCALE %x %x", scale_x, scale_y);
+
+       for (unsigned int i=0; i<clip.rects.size(); ++i)
        {
        {
-               __u8 *srcptr=(__u8*)src.data;
-               __u8 *dstptr=(__u8*)data; // !!
-               __u32 pal[256];
+//             eDebug("clip rect: %d %d %d %d", clip.rects[i].x(), clip.rects[i].y(), clip.rects[i].width(), clip.rects[i].height());
+               eRect area = pos; /* pos is the virtual (pre-clipping) area on the dest, which can be larger/smaller than src if scaling is enabled */
+               area&=clip.rects[i];
+               area&=eRect(ePoint(0, 0), size());
+
+               if (area.empty())
+                       continue;
+
+               eRect srcarea = area;
+               srcarea.moveBy(-pos.x(), -pos.y());
+
+//             eDebug("srcarea before scale: %d %d %d %d",
+//                     srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
                
                
-               for (int i=0; i<256; ++i)
+               if (flag & blitScale)
+                       srcarea = eRect(srcarea.x() * FIX / scale_x, srcarea.y() * FIX / scale_y, srcarea.width() * FIX / scale_x, srcarea.height() * FIX / scale_y);
+
+//             eDebug("srcarea after scale: %d %d %d %d",
+//                     srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
+
+               if ((surface->data_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 && (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;
+                       eWarning("unimplemented: scale on non-accel surfaces");
+                       continue;
                }
                }
-       
-               srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
-               dstptr+=area.left()*bypp+area.top()*stride;
-               for (int y=0; y<area.height(); y++)
+
+               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;
-                               __u32 *dst=(__u32*)dstptr;
-                                       // use duff's device here!
-                               while (width--)
+                               if (flag & (blitAlphaTest|blitAlphaBlend))
                                {
                                {
-                                       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++=pal[*src++];
-                               }
-                       } else
+                                               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))
+               {
+                       __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; y<area.height(); y++)
+                       {
+                               if (flag & blitAlphaTest)
+                               {
+                                       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);
+#undef BLEND
+
+                                               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++)
                        {
                                int width=area.width();
                        {
                                int width=area.width();
-                               unsigned char *src=(unsigned char*)srcptr;
+                               unsigned char *psrc=(unsigned char*)srcptr;
                                __u32 *dst=(__u32*)dstptr;
                                __u32 *dst=(__u32*)dstptr;
-                               while (width--)
-                                       *dst++=pal[*src++];
+                               if (flag & blitAlphaTest)
+                                       blit_8i_to_32_at(dst, psrc, pal, width);
+                               else if (flag & blitAlphaBlend)
+                                       blit_8i_to_32_ab(dst, psrc, pal, width);
+                               else
+                                       blit_8i_to_32(dst, psrc, pal, width);
+                               srcptr+=src.surface->stride;
+                               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)
 {
 void gPixmap::mergePalette(const gPixmap &target)
 {
-       if ((!clut.colors) || (!target.clut.colors))
+       if ((!surface->clut.colors) || (!target.surface->clut.colors))
                return;
                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[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
 {
 }
 
 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++)
        {
        int difference=1<<30, best_choice=0;
        for (int t=0; t<colors; t++)
        {
@@ -240,56 +609,30 @@ gColor gPalette::findColor(const gRGB &rgb) const
                ttd+=td;
                if (ttd>=difference)
                        continue;
                ttd+=td;
                if (ttd>=difference)
                        continue;
+               if (!ttd)
+                       return t;
                difference=ttd;
                best_choice=t;
        }
        return best_choice;
 }
 
                difference=ttd;
                best_choice=t;
        }
        return best_choice;
 }
 
-gPixmap::gPixmap(): ref(0)
-{
-}
+DEFINE_REF(gPixmap);
 
 gPixmap::~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);
 }
 }
+