SDL: add input support, use SDL mainloop in a thread
[enigma2.git] / lib / gdi / gpixmap.cpp
1 #include <cstdlib>
2 #include <cstring>
3 #include <lib/gdi/gpixmap.h>
4 #include <lib/gdi/region.h>
5 #include <lib/gdi/accel.h>
6 #include <byteswap.h>
7
8 #ifndef BYTE_ORDER
9 #error "no BYTE_ORDER defined!"
10 #endif
11
12 gLookup::gLookup()
13         :size(0), lookup(0)
14 {
15 }
16
17 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
18         :size(0), lookup(0)
19 {
20         build(size, pal, start, end);
21 }
22
23 void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
24 {
25         if (lookup)
26         {
27                 delete [] lookup;
28                 lookup=0;
29                 size=0;
30         }
31         size=_size;
32         if (!size)
33                 return;
34         lookup=new gColor[size];
35         
36         for (int i=0; i<size; i++)
37         {
38                 gRGB col;
39                 if (i)
40                 {
41                         int rdiff=-start.r+end.r;
42                         int gdiff=-start.g+end.g;
43                         int bdiff=-start.b+end.b;
44                         int adiff=-start.a+end.a;
45                         rdiff*=i; rdiff/=(size-1);
46                         gdiff*=i; gdiff/=(size-1);
47                         bdiff*=i; bdiff/=(size-1);
48                         adiff*=i; adiff/=(size-1);
49                         col.r=start.r+rdiff;
50                         col.g=start.g+gdiff;
51                         col.b=start.b+bdiff;
52                         col.a=start.a+adiff;
53                 } else
54                         col=start;
55                 lookup[i]=pal.findColor(col);
56         }
57 }
58
59 gSurface::gSurface()
60 {
61         x = 0;
62         y = 0;
63         bpp = 0;
64         bypp = 0;
65         stride = 0;
66         data = 0;
67         data_phys = 0;
68         clut.colors = 0;
69         clut.data = 0;
70         type = 0;
71 }
72
73 gSurface::gSurface(eSize size, int _bpp, int accel)
74 {
75         x = size.width();
76         y = size.height();
77         bpp = _bpp;
78
79         switch (bpp)
80         {
81         case 8:
82                 bypp = 1;
83                 break;
84         case 15:
85         case 16:
86                 bypp = 2;
87                 break;
88         case 24:                // never use 24bit mode
89         case 32:
90                 bypp = 4;
91                 break;
92         default:
93                 bypp = (bpp+7)/8;
94         }
95
96         stride = x*bypp;
97         
98         data = 0;
99         data_phys = 0;
100         
101         if (accel)
102         {
103                 stride += 63;
104                 stride &=~63;
105                 
106                 int pal_size = 0;
107                 if (bpp == 8)
108                         pal_size = 256 * 4;
109                 
110                 if (gAccel::getInstance())
111                         eDebug("accel memory: %d", gAccel::getInstance()->accelAlloc(data, data_phys, y * stride + pal_size));
112                 else
113                         eDebug("no accel available");
114         }
115         
116         clut.colors = 0;
117         clut.data = 0;
118
119         if (!data)
120                 data = new unsigned char [y * stride];
121         
122         type = 1;
123 }
124
125 gSurface::~gSurface()
126 {
127         if (type)
128         {
129                 if (data_phys)
130                         gAccel::getInstance()->accelFree(data_phys);
131                 else
132                         delete [] (unsigned char*)data;
133
134                 delete [] clut.data;
135         }
136 }
137
138 gPixmap *gPixmap::lock()
139 {
140         contentlock.lock(1);
141         return this;
142 }
143
144 void gPixmap::unlock()
145 {
146         contentlock.unlock(1);
147 }
148
149 void gPixmap::fill(const gRegion &region, const gColor &color)
150 {
151         unsigned int i;
152         for (i=0; i<region.rects.size(); ++i)
153         {
154                 const eRect &area = region.rects[i];
155                 if (area.empty())
156                         continue;
157
158                 if (surface->bpp == 8)
159                 {
160                         for (int y=area.top(); y<area.bottom(); y++)
161                                 memset(((__u8*)surface->data)+y*surface->stride+area.left(), color.color, area.width());
162                 } else if (surface->bpp == 16)
163                 {
164                         __u32 icol;
165
166                         if (surface->clut.data && color < surface->clut.colors)
167                                 icol=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
168                         else
169                                 icol=0x10101*color;
170 #if BYTE_ORDER == LITTLE_ENDIAN
171                         __u16 col = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
172 #else
173                         __u16 col = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
174 #endif
175                         for (int y=area.top(); y<area.bottom(); y++)
176                         {
177                                 __u16 *dst=(__u16*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
178                                 int x=area.width();
179                                 while (x--)
180                                         *dst++=col;
181                         }
182                 } else if (surface->bpp == 32)
183                 {
184                         __u32 col;
185
186                         if (surface->clut.data && color < surface->clut.colors)
187                                 col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
188                         else
189                                 col=0x10101*color;
190                         
191                         col^=0xFF000000;
192                         
193                         if (surface->data_phys && gAccel::getInstance())
194                                 if (!gAccel::getInstance()->fill(surface,  area, col))
195                                         continue;
196
197                         for (int y=area.top(); y<area.bottom(); y++)
198                         {
199                                 __u32 *dst=(__u32*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
200                                 int x=area.width();
201                                 while (x--)
202                                         *dst++=col;
203                         }
204                 }       else
205                         eWarning("couldn't fill %d bpp", surface->bpp);
206         }
207 }
208
209 void gPixmap::fill(const gRegion &region, const gRGB &color)
210 {
211         unsigned int i;
212         for (i=0; i<region.rects.size(); ++i)
213         {
214                 const eRect &area = region.rects[i];
215                 if (area.empty())
216                         continue;
217
218                 if (surface->bpp == 32)
219                 {
220                         __u32 col;
221
222                         col = color.argb();
223                         col^=0xFF000000;
224
225                         if (surface->data_phys && gAccel::getInstance())
226                                 if (!gAccel::getInstance()->fill(surface,  area, col))
227                                         continue;
228
229                         for (int y=area.top(); y<area.bottom(); y++)
230                         {
231                                 __u32 *dst=(__u32*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
232                                 int x=area.width();
233                                 while (x--)
234                                         *dst++=col;
235                         }
236                 } else if (surface->bpp == 16)
237                 {
238                         __u32 icol = color.argb();
239 #if BYTE_ORDER == LITTLE_ENDIAN
240                         __u16 col = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
241 #else
242                         __u16 col = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
243 #endif
244                         for (int y=area.top(); y<area.bottom(); y++)
245                         {
246                                 __u16 *dst=(__u16*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
247                                 int x=area.width();
248                                 while (x--)
249                                         *dst++=col;
250                         }
251                 }       else
252                         eWarning("couldn't rgbfill %d bpp", surface->bpp);
253         }
254 }
255
256 static inline void blit_8i_to_32(__u32 *dst, __u8 *src, __u32 *pal, int width)
257 {
258         while (width--)
259                 *dst++=pal[*src++];
260 }
261
262 static inline void blit_8i_to_32_at(__u32 *dst, __u8 *src, __u32 *pal, int width)
263 {
264         while (width--)
265         {
266                 if (!(pal[*src]&0x80000000))
267                 {
268                         src++;
269                         dst++;
270                 } else
271                         *dst++=pal[*src++];
272         }
273 }
274
275 static inline void blit_8i_to_16(__u16 *dst, __u8 *src, __u32 *pal, int width)
276 {
277         while (width--)
278                 *dst++=pal[*src++] & 0xFFFF;
279 }
280
281 static inline void blit_8i_to_16_at(__u16 *dst, __u8 *src, __u32 *pal, int width)
282 {
283         while (width--)
284         {
285                 if (!(pal[*src]&0x80000000))
286                 {
287                         src++;
288                         dst++;
289                 } else
290                         *dst++=pal[*src++] & 0xFFFF;
291         }
292 }
293
294                 /* WARNING, this function is not endian safe! */
295 static void blit_8i_to_32_ab(__u32 *dst, __u8 *src, __u32 *pal, int width)
296 {
297         while (width--)
298         {
299 #define BLEND(x, y, a) (y + (((x-y) * a)>>8))
300                 __u32 srccol = pal[*src++];
301                 __u32 dstcol = *dst;
302                 unsigned char sb = srccol & 0xFF;
303                 unsigned char sg = (srccol >> 8) & 0xFF;
304                 unsigned char sr = (srccol >> 16) & 0xFF;
305                 unsigned char sa = (srccol >> 24) & 0xFF;
306
307                 unsigned char db = dstcol & 0xFF;
308                 unsigned char dg = (dstcol >> 8) & 0xFF;
309                 unsigned char dr = (dstcol >> 16) & 0xFF;
310                 unsigned char da = (dstcol >> 24) & 0xFF;
311
312                 da = BLEND(0xFF, da, sa) & 0xFF;
313                 dr = BLEND(sr, dr, sa) & 0xFF;
314                 dg = BLEND(sg, dg, sa) & 0xFF;
315                 db = BLEND(sb, db, sa) & 0xFF;
316
317 #undef BLEND
318                 *dst++ = db | (dg << 8) | (dr << 16) | (da << 24);
319         }
320 }
321
322 #define FIX 0x10000
323
324 void gPixmap::blit(const gPixmap &src, const eRect &_pos, const gRegion &clip, int flag)
325 {
326 //      eDebug("blit: -> %d.%d %d:%d -> %d.%d %d:%d, flags=%d",
327 //              _pos.x(), _pos.y(), _pos.width(), _pos.height(),
328 //              clip.extends.x(), clip.extends.y(), clip.extends.width(), clip.extends.height(),
329 //              flag);
330         eRect pos = _pos;
331         
332 //      eDebug("source size: %d %d", src.size().width(), src.size().height());
333         
334         if (!(flag & blitScale)) /* pos' size is valid only when scaling */
335                 pos = eRect(pos.topLeft(), src.size());
336         else if (pos.size() == src.size()) /* no scaling required */
337                 flag &= ~blitScale;
338
339         int scale_x = FIX, scale_y = FIX;
340         
341         if (flag & blitScale)
342         {
343                 ASSERT(src.size().width());
344                 ASSERT(src.size().height());
345                 scale_x = pos.size().width() * FIX / src.size().width();
346                 scale_y = pos.size().height() * FIX / src.size().height();
347         }
348         
349 //      eDebug("SCALE %x %x", scale_x, scale_y);
350
351         for (unsigned int i=0; i<clip.rects.size(); ++i)
352         {
353 //              eDebug("clip rect: %d %d %d %d", clip.rects[i].x(), clip.rects[i].y(), clip.rects[i].width(), clip.rects[i].height());
354                 eRect area = pos; /* pos is the virtual (pre-clipping) area on the dest, which can be larger/smaller than src if scaling is enabled */
355                 area&=clip.rects[i];
356                 area&=eRect(ePoint(0, 0), size());
357
358                 if (area.empty())
359                         continue;
360
361                 eRect srcarea = area;
362                 srcarea.moveBy(-pos.x(), -pos.y());
363
364 //              eDebug("srcarea before scale: %d %d %d %d",
365 //                      srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
366                 
367                 if (flag & blitScale)
368                         srcarea = eRect(srcarea.x() * FIX / scale_x, srcarea.y() * FIX / scale_y, srcarea.width() * FIX / scale_x, srcarea.height() * FIX / scale_y);
369
370 //              eDebug("srcarea after scale: %d %d %d %d",
371 //                      srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
372
373                 if ((surface->data_phys && src.surface->data_phys) && (gAccel::getInstance()))
374                         if (!gAccel::getInstance()->blit(surface, src.surface, area, srcarea, flag))
375                                 continue;
376
377                 if (flag & blitScale)
378                 {
379                         eWarning("unimplemented: scale on non-accel surfaces");
380                         continue;
381                 }
382
383                 if ((surface->bpp == 8) && (src.surface->bpp==8))
384                 {
385                         __u8 *srcptr=(__u8*)src.surface->data;
386                         __u8 *dstptr=(__u8*)surface->data;
387
388                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
389                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
390                         for (int y=0; y<area.height(); y++)
391                         {
392                                 if (flag & (blitAlphaTest|blitAlphaBlend))
393                                 {
394                       // no real alphatest yet
395                                         int width=area.width();
396                                         unsigned char *src=(unsigned char*)srcptr;
397                                         unsigned char *dst=(unsigned char*)dstptr;
398                                                 // use duff's device here!
399                                         while (width--)
400                                         {
401                                                 if (!*src)
402                                                 {
403                                                         src++;
404                                                         dst++;
405                                                 } else
406                                                         *dst++=*src++;
407                                         }
408                                 } else
409                                         memcpy(dstptr, srcptr, area.width()*surface->bypp);
410                                 srcptr+=src.surface->stride;
411                                 dstptr+=surface->stride;
412                         }
413                 } else if ((surface->bpp == 32) && (src.surface->bpp==32))
414                 {
415                         __u32 *srcptr=(__u32*)src.surface->data;
416                         __u32 *dstptr=(__u32*)surface->data;
417
418                         srcptr+=srcarea.left()+srcarea.top()*src.surface->stride/4;
419                         dstptr+=area.left()+area.top()*surface->stride/4;
420                         for (int y=0; y<area.height(); y++)
421                         {
422                                 if (flag & blitAlphaTest)
423                                 {
424                                         int width=area.width();
425                                         unsigned long *src=(unsigned long*)srcptr;
426                                         unsigned long *dst=(unsigned long*)dstptr;
427
428                                         while (width--)
429                                         {
430                                                 if (!((*src)&0xFF000000))
431                                                 {
432                                                         src++;
433                                                         dst++;
434                                                 } else
435                                                         *dst++=*src++;
436                                         }
437                                 } else if (flag & blitAlphaBlend)
438                                 {
439                                         // uh oh. this is only until hardware accel is working.
440
441                                         int width=area.width();
442                                                         // ARGB color space!
443                                         unsigned char *src=(unsigned char*)srcptr;
444                                         unsigned char *dst=(unsigned char*)dstptr;
445
446 #define BLEND(x, y, a) (y + ((x-y) * a)/256)
447                                         while (width--)
448                                         {
449                                                 unsigned char sa = src[3];
450                                                 unsigned char sr = src[2];
451                                                 unsigned char sg = src[1];
452                                                 unsigned char sb = src[0];
453
454                                                 unsigned char da = dst[3];
455                                                 unsigned char dr = dst[2];
456                                                 unsigned char dg = dst[1];
457                                                 unsigned char db = dst[0];
458
459                                                 dst[3] = BLEND(0xFF, da, sa);
460                                                 dst[2] = BLEND(sr, dr, sa);
461                                                 dst[1] = BLEND(sg, dg, sa);
462                                                 dst[0] = BLEND(sb, db, sa);
463 #undef BLEND
464
465                                                 src += 4; dst += 4;
466                                         }
467                                 } else
468                                         memcpy(dstptr, srcptr, area.width()*surface->bypp);
469                                 srcptr+=src.surface->stride/4;
470                                 dstptr+=surface->stride/4;
471                         }
472                 } else if ((surface->bpp == 32) && (src.surface->bpp==8))
473                 {       
474                         __u8 *srcptr=(__u8*)src.surface->data;
475                         __u8 *dstptr=(__u8*)surface->data; // !!
476                         __u32 pal[256];
477
478                         for (int i=0; i<256; ++i)
479                         {
480                                 if (src.surface->clut.data && (i<src.surface->clut.colors))
481                                         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);
482                                 else
483                                         pal[i]=0x010101*i;
484                                 pal[i]^=0xFF000000;
485                         }
486
487                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
488                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
489                         for (int y=0; y<area.height(); y++)
490                         {
491                                 int width=area.width();
492                                 unsigned char *psrc=(unsigned char*)srcptr;
493                                 __u32 *dst=(__u32*)dstptr;
494                                 if (flag & blitAlphaTest)
495                                         blit_8i_to_32_at(dst, psrc, pal, width);
496                                 else if (flag & blitAlphaBlend)
497                                         blit_8i_to_32_ab(dst, psrc, pal, width);
498                                 else
499                                         blit_8i_to_32(dst, psrc, pal, width);
500                                 srcptr+=src.surface->stride;
501                                 dstptr+=surface->stride;
502                         }
503                 } else if ((surface->bpp == 16) && (src.surface->bpp==8))
504                 {
505                         __u8 *srcptr=(__u8*)src.surface->data;
506                         __u8 *dstptr=(__u8*)surface->data; // !!
507                         __u32 pal[256];
508
509                         for (int i=0; i<256; ++i)
510                         {
511                                 __u32 icol;
512                                 if (src.surface->clut.data && (i<src.surface->clut.colors))
513                                         icol=(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);
514                                 else
515                                         icol=0x010101*i;
516 #if BYTE_ORDER == LITTLE_ENDIAN
517                                 pal[i] = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
518 #else
519                                 pal[i] = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
520 #endif
521                                 pal[i]^=0xFF000000;
522                         }
523
524                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
525                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
526
527                         if (flag & blitAlphaBlend)
528                                 eWarning("ignore unsupported 8bpp -> 16bpp alphablend!");
529
530                         for (int y=0; y<area.height(); y++)
531                         {
532                                 int width=area.width();
533                                 unsigned char *psrc=(unsigned char*)srcptr;
534                                 __u16 *dst=(__u16*)dstptr;
535                                 if (flag & blitAlphaTest)
536                                         blit_8i_to_16_at(dst, psrc, pal, width);
537                                 else
538                                         blit_8i_to_16(dst, psrc, pal, width);
539                                 srcptr+=src.surface->stride;
540                                 dstptr+=surface->stride;
541                         }
542                 } else if ((surface->bpp == 16) && (src.surface->bpp==32))
543                 {
544                         __u8 *srcptr=(__u8*)src.surface->data;
545                         __u8 *dstptr=(__u8*)surface->data;
546
547                         srcptr+=srcarea.left()+srcarea.top()*src.surface->stride;
548                         dstptr+=area.left()+area.top()*surface->stride;
549
550                         if (flag & blitAlphaBlend)
551                                 eWarning("ignore unsupported 32bpp -> 16bpp alphablend!");
552
553                         for (int y=0; y<area.height(); y++)
554                         {
555                                 int width=area.width();
556                                 __u32 *srcp=(__u32*)srcptr;
557                                 __u16 *dstp=(__u16*)dstptr;
558
559                                 if (flag & blitAlphaTest)
560                                 {
561                                         while (width--)
562                                         {
563                                                 if (!((*srcp)&0xFF000000))
564                                                 {
565                                                         srcp++;
566                                                         dstp++;
567                                                 } else
568                                                 {
569                                                         __u32 icol = *srcp++;
570 #if BYTE_ORDER == LITTLE_ENDIAN
571                                                         *dstp++ = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
572 #else
573                                                         *dstp++ = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
574 #endif
575                                                 }
576                                         }
577                                 } else
578                                 {
579                                         while (width--)
580                                         {
581                                                 __u32 icol = *srcp++;
582 #if BYTE_ORDER == LITTLE_ENDIAN
583                                                 *dstp++ = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
584 #else
585                                                 *dstp++ = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
586 #endif
587                                         }
588                                 }
589                                 srcptr+=src.surface->stride;
590                                 dstptr+=surface->stride;
591                         }
592                 } else
593                         eWarning("cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp);
594         }
595 }
596
597 #undef FIX
598
599 void gPixmap::mergePalette(const gPixmap &target)
600 {
601         if ((!surface->clut.colors) || (!target.surface->clut.colors))
602                 return;
603
604         gColor *lookup=new gColor[surface->clut.colors];
605
606         for (int i=0; i<surface->clut.colors; i++)
607                 lookup[i].color=target.surface->clut.findColor(surface->clut.data[i]);
608         
609         delete [] surface->clut.data;
610         surface->clut.colors=target.surface->clut.colors;
611         surface->clut.data=new gRGB[surface->clut.colors];
612         memcpy(surface->clut.data, target.surface->clut.data, sizeof(gRGB)*surface->clut.colors);
613
614         __u8 *dstptr=(__u8*)surface->data;
615
616         for (int ay=0; ay<surface->y; ay++)
617         {
618                 for (int ax=0; ax<surface->x; ax++)
619                         dstptr[ax]=lookup[dstptr[ax]];
620                 dstptr+=surface->stride;
621         }
622         
623         delete [] lookup;
624 }
625
626 static inline int sgn(int a)
627 {
628         if (a < 0)
629                 return -1;
630         else if (!a)
631                 return 0;
632         else
633                 return 1;
634 }
635
636 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color)
637 {
638         __u8 *srf8 = 0;
639         __u16 *srf16 = 0;
640         __u32 *srf32 = 0;
641         int stride = surface->stride;
642
643         if (clip.rects.empty())
644                 return;
645
646         __u16 col16;
647         __u32 col = 0;
648         if (surface->bpp == 8)
649                 srf8 = (__u8*)surface->data;
650         else
651         {
652                 srf32 = (__u32*)surface->data;
653                 if (surface->clut.data && color < surface->clut.colors)
654                         col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
655                 else
656                         col=0x10101*color;
657                 col^=0xFF000000;
658         }
659
660         if (surface->bpp == 16)
661 #if BYTE_ORDER == LITTLE_ENDIAN
662                 col16=bswap_16(((col & 0xFF) >> 3) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF0000) >> 19);
663 #else
664                 col16=((col & 0xFF) >> 3) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF0000) >> 19;
665 #endif
666
667         int xa = start.x(), ya = start.y(), xb = dst.x(), yb = dst.y();
668         int dx, dy, x, y, s1, s2, e, temp, swap, i;
669         dy=abs(yb-ya);
670         dx=abs(xb-xa);
671         s1=sgn(xb-xa);
672         s2=sgn(yb-ya);
673         x=xa;
674         y=ya;
675         if (dy>dx)
676         {
677                 temp=dx;
678                 dx=dy;
679                 dy=temp;
680                 swap=1;
681         } else
682                 swap=0;
683         e = 2*dy-dx;
684
685         int lasthit = 0;
686         for(i=1; i<=dx; i++)
687         {
688                                 /* i don't like this clipping loop, but the only */
689                                 /* other choice i see is to calculate the intersections */
690                                 /* before iterating through the pixels. */
691                                 
692                                 /* one could optimize this because of the ordering */
693                                 /* of the bands. */
694                                 
695                 lasthit = 0;
696                 int a = lasthit;
697                 
698                         /* if last pixel was invisble, first check bounding box */
699                 if (a == -1)
700                 {
701                                 /* check if we just got into the bbox again */
702                         if (clip.extends.contains(x, y))
703                                 lasthit = a = 0;
704                         else
705                                 goto fail;
706                 } else if (!clip.rects[a].contains(x, y))
707                 {
708                         do
709                         {
710                                 ++a;
711                                 if ((unsigned int)a == clip.rects.size())
712                                         a = 0;
713                                 if (a == lasthit)
714                                 {
715                                         goto fail;
716                                         lasthit = -1;
717                                 }
718                         } while (!clip.rects[a].contains(x, y));
719                         lasthit = a;
720                 }
721
722                 if (srf8)
723                         srf8[y * stride + x] = color;
724                 else if (srf16)
725                         srf16[y * stride/2 + x] = col16;
726                 else
727                         srf32[y * stride/4 + x] = col;
728 fail:
729                 while (e>=0)
730                 {
731                         if (swap==1)
732                                 x+=s1;
733                         else
734                                 y+=s2;
735                         e-=2*dx;
736                 }
737
738                 if (swap==1)
739                         y+=s2;
740                 else
741                         x+=s1;
742                 e+=2*dy;
743         }
744 }
745
746 gColor gPalette::findColor(const gRGB &rgb) const
747 {
748                 /* grayscale? */
749         if (!data)
750                 return (rgb.r + rgb.g + rgb.b) / 3;
751         
752         int difference=1<<30, best_choice=0;
753         for (int t=0; t<colors; t++)
754         {
755                 int ttd;
756                 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
757                 ttd=td;
758                 if (ttd>=difference)
759                         continue;
760                 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
761                 ttd+=td;
762                 if (ttd>=difference)
763                         continue;
764                 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
765                 ttd+=td;
766                 if (ttd>=difference)
767                         continue;
768                 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
769                 ttd+=td;
770                 if (ttd>=difference)
771                         continue;
772                 if (!ttd)
773                         return t;
774                 difference=ttd;
775                 best_choice=t;
776         }
777         return best_choice;
778 }
779
780 DEFINE_REF(gPixmap);
781
782 gPixmap::~gPixmap()
783 {
784         if (must_delete_surface)
785                 delete surface;
786 }
787
788 gPixmap::gPixmap(gSurface *surface)
789         :surface(surface), must_delete_surface(false)
790 {
791 }
792
793 gPixmap::gPixmap(eSize size, int bpp, int accel)
794         :must_delete_surface(true)
795 {
796         surface = new gSurface(size, bpp, accel);
797 }
798