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