bcdd8346716e29fc2b66fa45734dd56a4ed5d531
[vuplus_dvbapp] / 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
325 void gPixmap::blit(const gPixmap &src, const eRect &_pos, const gRegion &clip, int flag)
326 {
327 //      eDebug("blit: -> %d.%d %d:%d -> %d.%d %d:%d, flags=%d",
328 //              _pos.x(), _pos.y(), _pos.width(), _pos.height(),
329 //              clip.extends.x(), clip.extends.y(), clip.extends.width(), clip.extends.height(),
330 //              flag);
331         eRect pos = _pos;
332         
333 //      eDebug("source size: %d %d", src.size().width(), src.size().height());
334         
335         if (!(flag & blitScale)) /* pos' size is valid only when scaling */
336                 pos = eRect(pos.topLeft(), src.size());
337         else if (pos.size() == src.size()) /* no scaling required */
338                 flag &= ~blitScale;
339
340         int scale_x = FIX, scale_y = FIX;
341         
342         if (flag & blitScale)
343         {
344                 ASSERT(src.size().width());
345                 ASSERT(src.size().height());
346                 scale_x = pos.size().width() * FIX / src.size().width();
347                 scale_y = pos.size().height() * FIX / src.size().height();
348         }
349         
350 //      eDebug("SCALE %x %x", scale_x, scale_y);
351
352         for (unsigned int i=0; i<clip.rects.size(); ++i)
353         {
354 //              eDebug("clip rect: %d %d %d %d", clip.rects[i].x(), clip.rects[i].y(), clip.rects[i].width(), clip.rects[i].height());
355                 eRect area = pos; /* pos is the virtual (pre-clipping) area on the dest, which can be larger/smaller than src if scaling is enabled */
356                 area&=clip.rects[i];
357                 area&=eRect(ePoint(0, 0), size());
358
359                 if (area.empty())
360                         continue;
361
362                 eRect srcarea = area;
363                 srcarea.moveBy(-pos.x(), -pos.y());
364
365 //              eDebug("srcarea before scale: %d %d %d %d",
366 //                      srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
367                 
368                 if (flag & blitScale)
369                         srcarea = eRect(srcarea.x() * FIX / scale_x, srcarea.y() * FIX / scale_y, srcarea.width() * FIX / scale_x, srcarea.height() * FIX / scale_y);
370
371 //              eDebug("srcarea after scale: %d %d %d %d",
372 //                      srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
373
374                 if ((surface->data_phys && src.surface->data_phys) && (gAccel::getInstance()))
375                         if (!gAccel::getInstance()->blit(surface, src.surface, area, srcarea, flag))
376                                 continue;
377
378                 if (flag & blitScale)
379                 {
380                         eWarning("unimplemented: scale on non-accel surfaces");
381                         continue;
382                 }
383
384 #ifdef SET_RIGHT_HALF_VFD_SKIN
385                 if ((surface->bpp == 8) && (src.surface->bpp==8))
386                 {
387                         __u8 *srcptr=(__u8*)src.surface->data;
388                         __u8 *dstptr=(__u8*)surface->data;
389                         __u8 *nomptr = new __u8[area.width()];
390                         unsigned char gray_max = 0;
391                         unsigned char gray_min = 255;
392                         unsigned char index = 0;
393                         unsigned char gray_value = 0;
394                         gRGB pixdata;
395 //                      printf("[bilt]srcarea.left:%d, src.surface->bypp : %d,srcarea.top() :%d,src.surface->stride : %d\n",srcarea.left(),src.surface->bypp,srcarea.top(),src.surface->stride);
396                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
397 //                      nomptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
398                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
399                         for (int y=0; y<area.height(); y++)
400                         {
401                                 for(int x=0;x<area.width();x++)
402                                 {
403                                         index = (unsigned char)(*(srcptr+x+y*src.surface->stride));
404                                         pixdata = src.surface->clut.data[index];
405                                         gray_value = ((pixdata.r+pixdata.g +pixdata.b)/3);
406 //                                      printf("%3d ",gray_value);
407                                         if(gray_value > gray_max)
408                                                 gray_max = gray_value;
409                                         if(gray_value < gray_min)
410                                                 gray_min = gray_value;
411                                 }
412 //                              printf("\n");
413                         }
414 //                      printf("\n[bilt] ### gray_min : %d, gray_max : %d\n\n",gray_min,gray_max);
415                         for (int y=0; y<area.height(); y++)
416                         {
417                                 for(int x=0;x<area.width();x++)
418                                 {
419                                         pixdata = src.surface->clut.data[*(srcptr+x)];
420                                         gray_value = ((pixdata.r+pixdata.g +pixdata.b)/3);
421                                         if(gray_max==gray_min)
422                                                 *(nomptr+x)=gray_value;
423                                         else if(y == 0 || y == area.height()-1 || x == 0 || x == area.width()-1)
424                                                 *(nomptr+x) = 255;
425                                         else
426                                                 *(nomptr+x)=( ((gray_value - gray_min)*255)/(gray_max-gray_min) );
427 //                                      printf("%3d ",*(nomptr+x));
428                                 }
429 //                              printf("\n");
430                                 if (flag & (blitAlphaTest|blitAlphaBlend))
431                                 {
432                       // no real alphatest yet
433                                         int width=area.width();
434 //                                      unsigned char *src=(unsigned char*)srcptr;
435                                         unsigned char *src=(unsigned char*)nomptr;
436                                         unsigned char *dst=(unsigned char*)dstptr;
437                                                 // use duff's device here!
438                                         while (width--)
439                                         {
440                                                 if (!*src)
441                                                 {
442                                                         src++;
443                                                         dst++;
444                                                 } else
445                                                         *dst++=*src++;
446                                         }
447                                 } else
448 //                                      memcpy(dstptr, srcptr, area.width()*surface->bypp);
449                                         memcpy(dstptr, nomptr, area.width()*surface->bypp);
450                                 srcptr+=src.surface->stride;
451                                 dstptr+=surface->stride;
452                         }
453                         delete [] nomptr;
454 #else
455                 if ((surface->bpp == 8) && (src.surface->bpp==8))
456                 {
457                         __u8 *srcptr=(__u8*)src.surface->data;
458                         __u8 *dstptr=(__u8*)surface->data;
459
460                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
461                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
462                         for (int y=0; y<area.height(); y++)
463                         {
464                                 if (flag & (blitAlphaTest|blitAlphaBlend))
465                                 {
466                       // no real alphatest yet
467                                         int width=area.width();
468                                         unsigned char *src=(unsigned char*)srcptr;
469                                         unsigned char *dst=(unsigned char*)dstptr;
470                                                 // use duff's device here!
471                                         while (width--)
472                                         {
473                                                 if (!*src)
474                                                 {
475                                                         src++;
476                                                         dst++;
477                                                 } else
478                                                         *dst++=*src++;
479                                         }
480                                 } else
481                                         memcpy(dstptr, srcptr, area.width()*surface->bypp);
482                                 srcptr+=src.surface->stride;
483                                 dstptr+=surface->stride;
484                         }
485 #endif
486                 } else if ((surface->bpp == 32) && (src.surface->bpp==32))
487                 {
488                         __u32 *srcptr=(__u32*)src.surface->data;
489                         __u32 *dstptr=(__u32*)surface->data;
490
491                         srcptr+=srcarea.left()+srcarea.top()*src.surface->stride/4;
492                         dstptr+=area.left()+area.top()*surface->stride/4;
493                         for (int y=0; y<area.height(); y++)
494                         {
495                                 if (flag & blitAlphaTest)
496                                 {
497                                         int width=area.width();
498                                         unsigned long *src=(unsigned long*)srcptr;
499                                         unsigned long *dst=(unsigned long*)dstptr;
500
501                                         while (width--)
502                                         {
503                                                 if (!((*src)&0xFF000000))
504                                                 {
505                                                         src++;
506                                                         dst++;
507                                                 } else
508                                                         *dst++=*src++;
509                                         }
510                                 } else if (flag & blitAlphaBlend)
511                                 {
512                                         // uh oh. this is only until hardware accel is working.
513
514                                         int width=area.width();
515                                                         // ARGB color space!
516                                         unsigned char *src=(unsigned char*)srcptr;
517                                         unsigned char *dst=(unsigned char*)dstptr;
518
519 #define BLEND(x, y, a) (y + ((x-y) * a)/256)
520                                         while (width--)
521                                         {
522                                                 unsigned char sa = src[3];
523                                                 unsigned char sr = src[2];
524                                                 unsigned char sg = src[1];
525                                                 unsigned char sb = src[0];
526
527                                                 unsigned char da = dst[3];
528                                                 unsigned char dr = dst[2];
529                                                 unsigned char dg = dst[1];
530                                                 unsigned char db = dst[0];
531
532                                                 dst[3] = BLEND(0xFF, da, sa);
533                                                 dst[2] = BLEND(sr, dr, sa);
534                                                 dst[1] = BLEND(sg, dg, sa);
535                                                 dst[0] = BLEND(sb, db, sa);
536 #undef BLEND
537
538                                                 src += 4; dst += 4;
539                                         }
540                                 } else
541                                         memcpy(dstptr, srcptr, area.width()*surface->bypp);
542                                 srcptr+=src.surface->stride/4;
543                                 dstptr+=surface->stride/4;
544                         }
545                 } else if ((surface->bpp == 32) && (src.surface->bpp==8))
546                 {       
547                         __u8 *srcptr=(__u8*)src.surface->data;
548                         __u8 *dstptr=(__u8*)surface->data; // !!
549                         __u32 pal[256];
550
551                         for (int i=0; i<256; ++i)
552                         {
553                                 if (src.surface->clut.data && (i<src.surface->clut.colors))
554                                         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);
555                                 else
556                                         pal[i]=0x010101*i;
557                                 pal[i]^=0xFF000000;
558                         }
559
560                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
561                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
562                         for (int y=0; y<area.height(); y++)
563                         {
564                                 int width=area.width();
565                                 unsigned char *psrc=(unsigned char*)srcptr;
566                                 __u32 *dst=(__u32*)dstptr;
567                                 if (flag & blitAlphaTest)
568                                         blit_8i_to_32_at(dst, psrc, pal, width);
569                                 else if (flag & blitAlphaBlend)
570                                         blit_8i_to_32_ab(dst, psrc, pal, width);
571                                 else
572                                         blit_8i_to_32(dst, psrc, pal, width);
573                                 srcptr+=src.surface->stride;
574                                 dstptr+=surface->stride;
575                         }
576                 } else if ((surface->bpp == 16) && (src.surface->bpp==8))
577                 {
578                         __u8 *srcptr=(__u8*)src.surface->data;
579                         __u8 *dstptr=(__u8*)surface->data; // !!
580                         __u32 pal[256];
581
582                         for (int i=0; i<256; ++i)
583                         {
584                                 __u32 icol;
585                                 if (src.surface->clut.data && (i<src.surface->clut.colors))
586                                         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);
587                                 else
588                                         icol=0x010101*i;
589 #if BYTE_ORDER == LITTLE_ENDIAN
590                                 pal[i] = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
591 #else
592                                 pal[i] = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
593 #endif
594                                 pal[i]^=0xFF000000;
595                         }
596
597                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
598                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
599
600                         if (flag & blitAlphaBlend)
601                                 eWarning("ignore unsupported 8bpp -> 16bpp alphablend!");
602
603                         for (int y=0; y<area.height(); y++)
604                         {
605                                 int width=area.width();
606                                 unsigned char *psrc=(unsigned char*)srcptr;
607                                 __u16 *dst=(__u16*)dstptr;
608                                 if (flag & blitAlphaTest)
609                                         blit_8i_to_16_at(dst, psrc, pal, width);
610                                 else
611                                         blit_8i_to_16(dst, psrc, pal, width);
612                                 srcptr+=src.surface->stride;
613                                 dstptr+=surface->stride;
614                         }
615                 } else if ((surface->bpp == 16) && (src.surface->bpp==32))
616                 {
617                         __u8 *srcptr=(__u8*)src.surface->data;
618                         __u8 *dstptr=(__u8*)surface->data;
619
620                         srcptr+=srcarea.left()+srcarea.top()*src.surface->stride;
621                         dstptr+=area.left()+area.top()*surface->stride;
622
623                         if (flag & blitAlphaBlend)
624                                 eWarning("ignore unsupported 32bpp -> 16bpp alphablend!");
625
626                         for (int y=0; y<area.height(); y++)
627                         {
628                                 int width=area.width();
629                                 __u32 *srcp=(__u32*)srcptr;
630                                 __u16 *dstp=(__u16*)dstptr;
631
632                                 if (flag & blitAlphaTest)
633                                 {
634                                         while (width--)
635                                         {
636                                                 if (!((*srcp)&0xFF000000))
637                                                 {
638                                                         srcp++;
639                                                         dstp++;
640                                                 } else
641                                                 {
642                                                         __u32 icol = *srcp++;
643 #if BYTE_ORDER == LITTLE_ENDIAN
644                                                         *dstp++ = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
645 #else
646                                                         *dstp++ = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
647 #endif
648                                                 }
649                                         }
650                                 } else
651                                 {
652                                         while (width--)
653                                         {
654                                                 __u32 icol = *srcp++;
655 #if BYTE_ORDER == LITTLE_ENDIAN
656                                                 *dstp++ = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
657 #else
658                                                 *dstp++ = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
659 #endif
660                                         }
661                                 }
662                                 srcptr+=src.surface->stride;
663                                 dstptr+=surface->stride;
664                         }
665                 } else
666                         eWarning("cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp);
667         }
668 }
669
670 #undef FIX
671
672 void gPixmap::mergePalette(const gPixmap &target)
673 {
674         if ((!surface->clut.colors) || (!target.surface->clut.colors))
675                 return;
676
677         gColor *lookup=new gColor[surface->clut.colors];
678
679         for (int i=0; i<surface->clut.colors; i++)
680                 lookup[i].color=target.surface->clut.findColor(surface->clut.data[i]);
681         
682         delete [] surface->clut.data;
683         surface->clut.colors=target.surface->clut.colors;
684         surface->clut.data=new gRGB[surface->clut.colors];
685         memcpy(surface->clut.data, target.surface->clut.data, sizeof(gRGB)*surface->clut.colors);
686
687         __u8 *dstptr=(__u8*)surface->data;
688
689         for (int ay=0; ay<surface->y; ay++)
690         {
691                 for (int ax=0; ax<surface->x; ax++)
692                         dstptr[ax]=lookup[dstptr[ax]];
693                 dstptr+=surface->stride;
694         }
695         
696         delete [] lookup;
697 }
698
699 static inline int sgn(int a)
700 {
701         if (a < 0)
702                 return -1;
703         else if (!a)
704                 return 0;
705         else
706                 return 1;
707 }
708
709 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color)
710 {
711         __u8 *srf8 = 0;
712         __u16 *srf16 = 0;
713         __u32 *srf32 = 0;
714         int stride = surface->stride;
715
716         if (clip.rects.empty())
717                 return;
718
719         __u16 col16;
720         __u32 col = 0;
721         if (surface->bpp == 8)
722                 srf8 = (__u8*)surface->data;
723         else
724         {
725                 srf32 = (__u32*)surface->data;
726                 if (surface->clut.data && color < surface->clut.colors)
727                         col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
728                 else
729                         col=0x10101*color;
730                 col^=0xFF000000;
731         }
732
733         if (surface->bpp == 16)
734 #if BYTE_ORDER == LITTLE_ENDIAN
735                 col16=bswap_16(((col & 0xFF) >> 3) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF0000) >> 19);
736 #else
737                 col16=((col & 0xFF) >> 3) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF0000) >> 19;
738 #endif
739
740         int xa = start.x(), ya = start.y(), xb = dst.x(), yb = dst.y();
741         int dx, dy, x, y, s1, s2, e, temp, swap, i;
742         dy=abs(yb-ya);
743         dx=abs(xb-xa);
744         s1=sgn(xb-xa);
745         s2=sgn(yb-ya);
746         x=xa;
747         y=ya;
748         if (dy>dx)
749         {
750                 temp=dx;
751                 dx=dy;
752                 dy=temp;
753                 swap=1;
754         } else
755                 swap=0;
756         e = 2*dy-dx;
757
758         int lasthit = 0;
759         for(i=1; i<=dx; i++)
760         {
761                                 /* i don't like this clipping loop, but the only */
762                                 /* other choice i see is to calculate the intersections */
763                                 /* before iterating through the pixels. */
764                                 
765                                 /* one could optimize this because of the ordering */
766                                 /* of the bands. */
767                                 
768                 lasthit = 0;
769                 int a = lasthit;
770                 
771                         /* if last pixel was invisble, first check bounding box */
772                 if (a == -1)
773                 {
774                                 /* check if we just got into the bbox again */
775                         if (clip.extends.contains(x, y))
776                                 lasthit = a = 0;
777                         else
778                                 goto fail;
779                 } else if (!clip.rects[a].contains(x, y))
780                 {
781                         do
782                         {
783                                 ++a;
784                                 if ((unsigned int)a == clip.rects.size())
785                                         a = 0;
786                                 if (a == lasthit)
787                                 {
788                                         goto fail;
789                                         lasthit = -1;
790                                 }
791                         } while (!clip.rects[a].contains(x, y));
792                         lasthit = a;
793                 }
794
795                 if (srf8)
796                         srf8[y * stride + x] = color;
797                 else if (srf16)
798                         srf16[y * stride/2 + x] = col16;
799                 else
800                         srf32[y * stride/4 + x] = col;
801 fail:
802                 while (e>=0)
803                 {
804                         if (swap==1)
805                                 x+=s1;
806                         else
807                                 y+=s2;
808                         e-=2*dx;
809                 }
810
811                 if (swap==1)
812                         y+=s2;
813                 else
814                         x+=s1;
815                 e+=2*dy;
816         }
817 }
818
819 gColor gPalette::findColor(const gRGB &rgb) const
820 {
821                 /* grayscale? */
822         if (!data)
823                 return (rgb.r + rgb.g + rgb.b) / 3;
824         
825         int difference=1<<30, best_choice=0;
826         for (int t=0; t<colors; t++)
827         {
828                 int ttd;
829                 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
830                 ttd=td;
831                 if (ttd>=difference)
832                         continue;
833                 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
834                 ttd+=td;
835                 if (ttd>=difference)
836                         continue;
837                 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
838                 ttd+=td;
839                 if (ttd>=difference)
840                         continue;
841                 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
842                 ttd+=td;
843                 if (ttd>=difference)
844                         continue;
845                 if (!ttd)
846                         return t;
847                 difference=ttd;
848                 best_choice=t;
849         }
850         return best_choice;
851 }
852
853 DEFINE_REF(gPixmap);
854
855 gPixmap::~gPixmap()
856 {
857         if (must_delete_surface)
858                 delete surface;
859 }
860
861 gPixmap::gPixmap(gSurface *surface)
862         :surface(surface), must_delete_surface(false)
863 {
864 }
865
866 gPixmap::gPixmap(eSize size, int bpp, int accel)
867         :must_delete_surface(true)
868 {
869         surface = new gSurface(size, bpp, accel);
870 }
871