Extrenal srt problem gst-1 solved.
[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 #include <byteswap.h>
7
8 #ifndef BYTE_ORDER
9 #error "no BYTE_ORDER defined!"
10 #endif
11
12 // #define GPIXMAP_DEBUG
13
14 #ifdef GPIXMAP_DEBUG
15 #       include "../base/benchmark.h"
16 #endif
17
18 gLookup::gLookup()
19         :size(0), lookup(0)
20 {
21 }
22
23 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
24         :size(0), lookup(0)
25 {
26         build(size, pal, start, end);
27 }
28
29 void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
30 {
31         if (lookup)
32         {
33                 delete [] lookup;
34                 lookup=0;
35                 size=0;
36         }
37         size=_size;
38         if (!size)
39                 return;
40         lookup=new gColor[size];
41
42         lookup[0] = pal.findColor(start);
43
44         const int rsize = end.r - start.r;
45         const int gsize = end.g - start.g;
46         const int bsize = end.b - start.b;
47         const int asize = end.a - start.a;
48         const int size_1 = size - 1;
49
50         for (int i=1; i<size; i++)
51         {
52                 gRGB col;
53                 int rdiff = (rsize * i) / size_1;
54                 int gdiff = (gsize * i) / size_1;
55                 int bdiff = (bsize * i) / size_1;
56                 int adiff = (asize * i) / size_1;
57                 col.r = start.r + rdiff;
58                 col.g = start.g + gdiff;
59                 col.b = start.b + bdiff;
60                 col.a = start.a + adiff;
61                 lookup[i] = pal.findColor(col);
62         }
63 }
64
65 gUnmanagedSurface::gUnmanagedSurface():
66         x(0), y(0), bpp(0), bypp(0), stride(0),
67         data(0),
68         data_phys(0)
69 {
70 }
71
72 gUnmanagedSurface::gUnmanagedSurface(int width, int height, int _bpp):
73         x(width),
74         y(height),
75         bpp(_bpp),
76         data(0),
77         data_phys(0)
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         stride = x*bypp;
96 }
97
98 #ifdef GPIXMAP_DEBUG
99 unsigned int pixmap_total_size = 0;
100 unsigned int pixmap_total_count = 0;
101 static void added_pixmap(int size)
102 {
103         ++pixmap_total_count;
104         pixmap_total_size += size;
105         eDebug("[gSurface] Added %dk, total %u pixmaps, %uk", size>>10, pixmap_total_count, pixmap_total_size>>10);
106 }
107 static void removed_pixmap(int size)
108 {
109         --pixmap_total_count;
110         pixmap_total_size -= size;
111         eDebug("[gSurface] Removed %dk, total %u pixmaps, %uk", size>>10, pixmap_total_count, pixmap_total_size>>10);
112 }
113 #else
114 static inline void added_pixmap(int size) {}
115 static inline void removed_pixmap(int size) {}
116 #endif
117
118 static bool is_a_candidate_for_accel(const gUnmanagedSurface* surface)
119 {
120         if (surface->stride < 48)
121                 return false;
122         switch (surface->bpp)
123         {
124                 case 8:
125                         return (surface->y * surface->stride) > 12000;
126                 case 32:
127                         return (surface->y * surface->stride) > 48000;
128                 default:
129                         return false;
130         }
131 }
132
133 gSurface::gSurface(int width, int height, int _bpp, int accel):
134         gUnmanagedSurface(width, height, _bpp)
135 {
136         if ((accel > gPixmap::accelAuto) ||
137                 ((accel == gPixmap::accelAuto) && (is_a_candidate_for_accel(this))))
138         {
139                 if (gAccel::getInstance()->accelAlloc(this) != 0)
140                                 eDebug("[gSurface] ERROR: accelAlloc failed");
141         }
142         if (!data)
143         {
144                 data = new unsigned char [y * stride];
145                 added_pixmap(y * stride);
146         }
147 }
148
149 gSurface::~gSurface()
150 {
151         gAccel::getInstance()->accelFree(this);
152         if (data)
153         {
154                 delete [] (unsigned char*)data;
155                 removed_pixmap(y * stride);
156         }
157         if (clut.data)
158         {
159                 delete [] clut.data;
160         }
161 }
162
163 void gPixmap::fill(const gRegion &region, const gColor &color)
164 {
165         unsigned int i;
166         for (i=0; i<region.rects.size(); ++i)
167         {
168                 const eRect &area = region.rects[i];
169                 if (area.empty())
170                         continue;
171
172                 if (surface->bpp == 8)
173                 {
174                         for (int y=area.top(); y<area.bottom(); y++)
175                                 memset(((__u8*)surface->data)+y*surface->stride+area.left(), color.color, area.width());
176                 } else if (surface->bpp == 16)
177                 {
178                         uint32_t icol;
179
180                         if (surface->clut.data && color < surface->clut.colors)
181                                 icol=surface->clut.data[color].argb();
182                         else
183                                 icol=0x10101*color;
184 #if BYTE_ORDER == LITTLE_ENDIAN
185                         uint16_t col = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
186 #else
187                         uint16_t col = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
188 #endif
189                         for (int y=area.top(); y<area.bottom(); y++)
190                         {
191                                 uint16_t *dst=(uint16_t*)(((uint8_t*)surface->data)+y*surface->stride+area.left()*surface->bypp);
192                                 int x=area.width();
193                                 while (x--)
194                                         *dst++=col;
195                         }
196                 } else if (surface->bpp == 32)
197                 {
198                         uint32_t col;
199
200                         if (surface->clut.data && color < surface->clut.colors)
201                                 col = surface->clut.data[color].argb();
202                         else
203                                 col = 0x10101 * color;
204
205                         col^=0xFF000000;
206
207                         if (surface->data_phys)
208                                 if (!gAccel::getInstance()->fill(surface,  area, col))
209                                         continue;
210
211                         for (int y=area.top(); y<area.bottom(); y++)
212                         {
213                                 uint32_t *dst=(uint32_t*)(((uint8_t*)surface->data)+y*surface->stride+area.left()*surface->bypp);
214                                 int x=area.width();
215                                 while (x--)
216                                         *dst++=col;
217                         }
218                 } else
219                         eWarning("[gPixmap] couldn't fill %d bpp", surface->bpp);
220         }
221 }
222
223 void gPixmap::fill(const gRegion &region, const gRGB &color)
224 {
225         unsigned int i;
226         for (i=0; i<region.rects.size(); ++i)
227         {
228                 const eRect &area = region.rects[i];
229                 if (area.empty())
230                         continue;
231
232                 if (surface->bpp == 32)
233                 {
234                         uint32_t col;
235
236                         col = color.argb();
237                         col^=0xFF000000;
238
239 #ifdef GPIXMAP_DEBUG
240                         Stopwatch s;
241 #endif
242                         if (surface->data_phys && (area.surface() > 20000))
243                                 if (!gAccel::getInstance()->fill(surface,  area, col)) {
244 #ifdef GPIXMAP_DEBUG
245                                         s.stop();
246                                         eDebug("[gPixmap] [BLITBENCH] accel fill %dx%d took %u us", area.width(), area.height(), s.elapsed_us());
247 #endif
248                                         continue;
249                                 }
250
251                         for (int y=area.top(); y<area.bottom(); y++)
252                         {
253                                 uint32_t *dst=(uint32_t*)(((uint8_t*)surface->data)+y*surface->stride+area.left()*surface->bypp);
254                                 int x=area.width();
255                                 while (x--)
256                                         *dst++=col;
257                         }
258 #ifdef GPIXMAP_DEBUG
259                         s.stop();
260                         eDebug("[gPixmap] [BLITBENCH] cpu fill %dx%d took %u us", area.width(), area.height(), s.elapsed_us());
261 #endif
262                 } else if (surface->bpp == 16)
263                 {
264                         uint32_t icol = color.argb();
265 #if BYTE_ORDER == LITTLE_ENDIAN
266                         uint16_t col = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
267 #else
268                         uint16_t col = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
269 #endif
270                         for (int y=area.top(); y<area.bottom(); y++)
271                         {
272                                 uint16_t *dst=(uint16_t*)(((uint8_t*)surface->data)+y*surface->stride+area.left()*surface->bypp);
273                                 int x=area.width();
274                                 while (x--)
275                                         *dst++=col;
276                         }
277                 } else
278                         eWarning("[gPixmap] couldn't rgbfill %d bpp", surface->bpp);
279         }
280 }
281
282 static inline void blit_8i_to_32(uint32_t *dst, const uint8_t *src, const uint32_t *pal, int width)
283 {
284         while (width--)
285                 *dst++=pal[*src++];
286 }
287
288 static inline void blit_8i_to_32_at(uint32_t *dst, const uint8_t *src, const uint32_t *pal, int width)
289 {
290         while (width--)
291         {
292                 if (!(pal[*src]&0x80000000))
293                 {
294                         src++;
295                         dst++;
296                 } else
297                         *dst++=pal[*src++];
298         }
299 }
300
301 static inline void blit_8i_to_16(uint16_t *dst, const uint8_t *src, const uint32_t *pal, int width)
302 {
303         while (width--)
304                 *dst++=pal[*src++] & 0xFFFF;
305 }
306
307 static inline void blit_8i_to_16_at(uint16_t *dst, const uint8_t *src, const uint32_t *pal, int width)
308 {
309         while (width--)
310         {
311                 if (!(pal[*src]&0x80000000))
312                 {
313                         src++;
314                         dst++;
315                 } else
316                         *dst++=pal[*src++] & 0xFFFF;
317         }
318 }
319
320 static void blit_8i_to_32_ab(gRGB *dst, const uint8_t *src, const gRGB *pal, int width)
321 {
322         while (width--)
323         {
324                 dst->alpha_blend(pal[*src++]);
325                 ++dst;
326         }
327 }
328
329 static void convert_palette(uint32_t* pal, const gPalette& clut)
330 {
331         int i = 0;
332         if (clut.data)
333         {
334                 while (i < clut.colors)
335                 {
336                         pal[i] = clut.data[i].argb() ^ 0xFF000000;
337                         ++i;
338                 }
339         }
340         for(; i != 256; ++i)
341         {
342                 pal[i] = (0x010101*i) | 0xFF000000;
343         }
344 }
345
346 #define FIX 0x10000
347
348 void gPixmap::blit(const gPixmap &src, const eRect &_pos, const gRegion &clip, int flag)
349 {
350         bool accel = (surface->data_phys && src.surface->data_phys);
351 //      eDebug("[gPixmap] blit: -> %d,%d+%d,%d -> %d,%d+%d,%d, flags=0x%x, accel=%d",
352 //              _pos.x(), _pos.y(), _pos.width(), _pos.height(),
353 //              clip.extends.x(), clip.extends.y(), clip.extends.width(), clip.extends.height(),
354 //              flag, accel);
355         eRect pos = _pos;
356
357 //      eDebug("[gPixmap] source size: %d %d", src.size().width(), src.size().height());
358
359         if (!(flag & blitScale)) /* pos' size is valid only when scaling */
360                 pos = eRect(pos.topLeft(), src.size());
361         else if (pos.size() == src.size()) /* no scaling required */
362                 flag &= ~blitScale;
363
364         int scale_x = FIX, scale_y = FIX;
365
366         if (flag & blitScale)
367         {
368                 ASSERT(src.size().width());
369                 ASSERT(src.size().height());
370                 scale_x = pos.size().width() * FIX / src.size().width();
371                 scale_y = pos.size().height() * FIX / src.size().height();
372                 if (flag & blitKeepAspectRatio)
373                 {
374                         if (scale_x > scale_y)
375                         {
376                                 pos = eRect(ePoint(pos.x() + (scale_x - scale_y) * pos.width() / (2 * FIX), pos.y()),
377                                         eSize(src.size().width() * pos.height() / src.size().height(), pos.height()));
378                                 scale_x = scale_y;
379
380                         }
381                         else
382                         {
383                                 pos = eRect(ePoint(pos.x(), pos.y()  + (scale_y - scale_x) * pos.height() / (2 * FIX)),
384                                         eSize(pos.width(), src.size().height() * pos.width() / src.size().width()));
385                                 scale_y = scale_x;
386                         }
387                 }
388         }
389
390 //      eDebug("[gPixmap] SCALE %x %x", scale_x, scale_y);
391
392         for (unsigned int i=0; i<clip.rects.size(); ++i)
393         {
394 //              eDebug("[gPixmap] clip rect: %d %d %d %d", clip.rects[i].x(), clip.rects[i].y(), clip.rects[i].width(), clip.rects[i].height());
395                 eRect area = pos; /* pos is the virtual (pre-clipping) area on the dest, which can be larger/smaller than src if scaling is enabled */
396                 area&=clip.rects[i];
397                 area&=eRect(ePoint(0, 0), size());
398
399                 if (area.empty())
400                         continue;
401
402                 eRect srcarea = area;
403                 srcarea.moveBy(-pos.x(), -pos.y());
404
405 //              eDebug("[gPixmap] srcarea before scale: %d %d %d %d",
406 //                      srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
407
408                 if (flag & blitScale)
409                         srcarea = eRect(srcarea.x() * FIX / scale_x, srcarea.y() * FIX / scale_y, srcarea.width() * FIX / scale_x, srcarea.height() * FIX / scale_y);
410
411 //              eDebug("[gPixmap] srcarea after scale: %d %d %d %d",
412 //                      srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
413
414                 if (accel)
415                 {
416                         /* we have hardware acceleration for this blit operation */
417                         if (flag & (blitAlphaTest | blitAlphaBlend))
418                         {
419                                 /* alpha blending is requested */
420                                 if (gAccel::getInstance()->hasAlphaBlendingSupport())
421                                 {
422                                         /* Hardware alpha blending is broken on the few
423                                          * boxes that support it, so only use it
424                                          * when scaling */
425                                         if (flag & blitScale)
426                                                 accel = true;
427                                         else if (flag & blitAlphaTest) /* Alpha test only on 8-bit */
428                                                 accel = (src.surface->bpp == 8);
429                                         else
430                                                 accel = false;
431                                 }
432                                 else
433                                 {
434                                         /* our hardware does not support alphablending */
435                                         accel = false;
436                                 }
437                         }
438                 }
439
440 #ifdef GPIXMAP_DEBUG
441                 Stopwatch s;
442 #endif
443                 if (accel) {
444                         if (!gAccel::getInstance()->blit(surface, src.surface, area, srcarea, flag)) {
445 #ifdef GPIXMAP_DEBUG
446                                 s.stop();
447                                 eDebug("[gPixmap] [BLITBENCH] accel blit took %u us", s.elapsed_us());
448 #endif
449                                 continue;
450                         }
451                 }
452
453                 if (flag & blitScale)
454                 {
455                         if ((surface->bpp == 32) && (src.surface->bpp==8))
456                         {
457                                 const uint8_t *srcptr = (uint8_t*)src.surface->data;
458                                 uint8_t *dstptr=(uint8_t*)surface->data; // !!
459                                 uint32_t pal[256];
460                                 convert_palette(pal, src.surface->clut);
461
462                                 const int src_stride = src.surface->stride;
463                                 srcptr += srcarea.left()*src.surface->bypp + srcarea.top()*src_stride;
464                                 dstptr += area.left()*surface->bypp + area.top()*surface->stride;
465                                 const int width = area.width();
466                                 const int height = area.height();
467                                 const int src_height = srcarea.height();
468                                 const int src_width = srcarea.width();
469                                 if (flag & blitAlphaTest)
470                                 {
471                                         for (int y = 0; y < height; ++y)
472                                         {
473                                                 const uint8_t *src_row_ptr = srcptr + (((y * src_height) / height) * src_stride);
474                                                 uint32_t *dst = (uint32_t*)dstptr;
475                                                 for (int x = 0; x < width; ++x)
476                                                 {
477                                                         uint32_t pixel = pal[src_row_ptr[(x *src_width) / width]];
478                                                         if (pixel & 0x80000000)
479                                                                 *dst = pixel;
480                                                         ++dst;
481                                                 }
482                                                 dstptr += surface->stride;
483                                         }
484                                 }
485                                 else if (flag & blitAlphaBlend)
486                                 {
487                                         for (int y = 0; y < height; ++y)
488                                         {
489                                                 const uint8_t *src_row_ptr = srcptr + (((y * src_height) / height) * src_stride);
490                                                 gRGB *dst = (gRGB*)dstptr;
491                                                 for (int x = 0; x < width; ++x)
492                                                 {
493                                                         dst->alpha_blend(pal[src_row_ptr[(x * src_width) / width]]);
494                                                         ++dst;
495                                                 }
496                                                 dstptr += surface->stride;
497                                         }
498                                 }
499                                 else
500                                 {
501                                         for (int y = 0; y < height; ++y)
502                                         {
503                                                 const uint8_t *src_row_ptr = srcptr + (((y * src_height) / height) * src_stride);
504                                                 uint32_t *dst = (uint32_t*)dstptr;
505                                                 for (int x = 0; x < width; ++x)
506                                                 {
507                                                         *dst = pal[src_row_ptr[(x * src_width) / width]];
508                                                         ++dst;
509                                                 }
510                                                 dstptr += surface->stride;
511                                         }
512                                 }
513                         }
514                         else if ((surface->bpp == 32) && (src.surface->bpp == 32))
515                         {
516                                 const int src_stride = src.surface->stride;
517                                 const uint8_t* srcptr = (const uint8_t*)src.surface->data + srcarea.left()*src.surface->bypp + srcarea.top()*src_stride;
518                                 uint8_t* dstptr = (uint8_t*)surface->data + area.left()*surface->bypp + area.top()*surface->stride;
519                                 const int width = area.width();
520                                 const int height = area.height();
521                                 const int src_height = srcarea.height();
522                                 const int src_width = srcarea.width();
523                                 if (flag & blitAlphaTest)
524                                 {
525                                         for (int y = 0; y < height; ++y)
526                                         {
527                                                 const uint32_t *src_row_ptr = (uint32_t*)(srcptr + (((y * src_height) / height) * src_stride));
528                                                 uint32_t *dst = (uint32_t*)dstptr;
529                                                 for (int x = 0; x < width; ++x)
530                                                 {
531                                                         uint32_t pixel = src_row_ptr[(x *src_width) / width];
532                                                         if (pixel & 0x80000000)
533                                                                 *dst = pixel;
534                                                         ++dst;
535                                                 }
536                                                 dstptr += surface->stride;
537                                         }
538                                 }
539                                 else if (flag & blitAlphaBlend)
540                                 {
541                                         for (int y = 0; y < height; ++y)
542                                         {
543                                                 const gRGB *src_row_ptr = (gRGB *)(srcptr + (((y * src_height) / height) * src_stride));
544                                                 gRGB *dst = (gRGB*)dstptr;
545                                                 for (int x = 0; x < width; ++x)
546                                                 {
547                                                         dst->alpha_blend(src_row_ptr[(x * src_width) / width]);
548                                                         ++dst;
549                                                 }
550                                                 dstptr += surface->stride;
551                                         }
552                                 }
553                                 else
554                                 {
555                                         for (int y = 0; y < height; ++y)
556                                         {
557                                                 const uint32_t *src_row_ptr = (uint32_t*)(srcptr + (((y * src_height) / height) * src_stride));
558                                                 uint32_t *dst = (uint32_t*)dstptr;
559                                                 for (int x = 0; x < width; ++x)
560                                                 {
561                                                         *dst = src_row_ptr[(x * src_width) / width];
562                                                         ++dst;
563                                                 }
564                                                 dstptr += surface->stride;
565                                         }
566                                 }
567                         }
568                         else
569                         {
570                                 eWarning("[gPixmap] unimplemented: scale on non-accel surface %d->%d bpp", src.surface->bpp, surface->bpp);
571                         }
572 #ifdef GPIXMAP_DEBUG
573                         s.stop();
574                         eDebug("[gPixmap] [BLITBENCH] CPU scale blit took %u us", s.elapsed_us());
575 #endif
576                         continue;
577                 }
578
579                 if ((surface->bpp == 8) && (src.surface->bpp == 8))
580                 {
581                         uint8_t *srcptr=(uint8_t*)src.surface->data;
582                         uint8_t *dstptr=(uint8_t*)surface->data;
583
584                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
585                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
586                         if (flag & (blitAlphaTest|blitAlphaBlend))
587                         {
588                                 for (int y = area.height(); y != 0; --y)
589                                 {
590                                         // no real alphatest yet
591                                         int width=area.width();
592                                         unsigned char *s = (unsigned char*)srcptr;
593                                         unsigned char *d = (unsigned char*)dstptr;
594                                         // use duff's device here!
595                                         while (width--)
596                                         {
597                                                 if (!*s)
598                                                 {
599                                                         s++;
600                                                         d++;
601                                                 }
602                                                 else
603                                                 {
604                                                         *d++ = *s++;
605                                                 }
606                                         }
607                                         srcptr += src.surface->stride;
608                                         dstptr += surface->stride;
609                                 }
610                         }
611                         else
612                         {
613                                 int linesize = area.width()*surface->bypp;
614                                 for (int y = area.height(); y != 0; --y)
615                                 {
616                                         memcpy(dstptr, srcptr, linesize);
617                                         srcptr += src.surface->stride;
618                                         dstptr += surface->stride;
619                                 }
620                         }
621                 }
622                 else if ((surface->bpp == 32) && (src.surface->bpp==32))
623                 {
624                         uint32_t *srcptr=(uint32_t*)src.surface->data;
625                         uint32_t *dstptr=(uint32_t*)surface->data;
626
627                         srcptr+=srcarea.left()+srcarea.top()*src.surface->stride/4;
628                         dstptr+=area.left()+area.top()*surface->stride/4;
629                         for (int y = area.height(); y != 0; --y)
630                         {
631                                 if (flag & blitAlphaTest)
632                                 {
633                                         int width=area.width();
634                                         unsigned long *src=(unsigned long*)srcptr;
635                                         unsigned long *dst=(unsigned long*)dstptr;
636                                         while (width--)
637                                         {
638                                                 if (!((*src)&0xFF000000))
639                                                 {
640                                                         src++;
641                                                         dst++;
642                                                 } else
643                                                         *dst++=*src++;
644                                         }
645                                 } else if (flag & blitAlphaBlend)
646                                 {
647                                         int width = area.width();
648                                         gRGB *src = (gRGB*)srcptr;
649                                         gRGB *dst = (gRGB*)dstptr;
650                                         while (width--)
651                                         {
652                                                 dst->alpha_blend(*src++);
653                                                 ++dst;
654                                         }
655                                 } else
656                                         memcpy(dstptr, srcptr, area.width()*surface->bypp);
657                                 srcptr = (uint32_t*)((uint8_t*)srcptr + src.surface->stride);
658                                 dstptr = (uint32_t*)((uint8_t*)dstptr + surface->stride);
659                         }
660                 }
661                 else if ((surface->bpp == 32) && (src.surface->bpp==8))
662                 {
663                         const uint8_t *srcptr = (uint8_t*)src.surface->data;
664                         uint8_t *dstptr=(uint8_t*)surface->data; // !!
665                         uint32_t pal[256];
666                         convert_palette(pal, src.surface->clut);
667
668                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
669                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
670                         const int width=area.width();
671                         for (int y = area.height(); y != 0; --y)
672                         {
673                                 if (flag & blitAlphaTest)
674                                         blit_8i_to_32_at((uint32_t*)dstptr, srcptr, pal, width);
675                                 else if (flag & blitAlphaBlend)
676                                         blit_8i_to_32_ab((gRGB*)dstptr, srcptr, (const gRGB*)pal, width);
677                                 else
678                                         blit_8i_to_32((uint32_t*)dstptr, srcptr, pal, width);
679                                 srcptr += src.surface->stride;
680                                 dstptr += surface->stride;
681                         }
682                 }
683                 else if ((surface->bpp == 16) && (src.surface->bpp==8))
684                 {
685                         uint8_t *srcptr=(uint8_t*)src.surface->data;
686                         uint8_t *dstptr=(uint8_t*)surface->data; // !!
687                         uint32_t pal[256];
688
689                         for (int i=0; i != 256; ++i)
690                         {
691                                 uint32_t icol;
692                                 if (src.surface->clut.data && (i<src.surface->clut.colors))
693                                         icol = src.surface->clut.data[i].argb();
694                                 else
695                                         icol=0x010101*i;
696 #if BYTE_ORDER == LITTLE_ENDIAN
697                                 pal[i] = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
698 #else
699                                 pal[i] = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
700 #endif
701                                 pal[i]^=0xFF000000;
702                         }
703
704                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
705                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
706
707                         if (flag & blitAlphaBlend)
708                                 eWarning("[gPixmap] ignore unsupported 8bpp -> 16bpp alphablend!");
709
710                         for (int y=0; y<area.height(); y++)
711                         {
712                                 int width=area.width();
713                                 unsigned char *psrc=(unsigned char*)srcptr;
714                                 uint16_t *dst=(uint16_t*)dstptr;
715                                 if (flag & blitAlphaTest)
716                                         blit_8i_to_16_at(dst, psrc, pal, width);
717                                 else
718                                         blit_8i_to_16(dst, psrc, pal, width);
719                                 srcptr+=src.surface->stride;
720                                 dstptr+=surface->stride;
721                         }
722                 }
723                 else if ((surface->bpp == 16) && (src.surface->bpp==32))
724                 {
725                         uint8_t *srcptr=(uint8_t*)src.surface->data;
726                         uint8_t *dstptr=(uint8_t*)surface->data;
727
728                         srcptr+=srcarea.left()+srcarea.top()*src.surface->stride;
729                         dstptr+=area.left()+area.top()*surface->stride;
730
731                         if (flag & blitAlphaBlend)
732                                 eWarning("[gPixmap] ignore unsupported 32bpp -> 16bpp alphablend!");
733
734                         for (int y=0; y<area.height(); y++)
735                         {
736                                 int width=area.width();
737                                 uint32_t *srcp=(uint32_t*)srcptr;
738                                 uint16_t *dstp=(uint16_t*)dstptr;
739
740                                 if (flag & blitAlphaTest)
741                                 {
742                                         while (width--)
743                                         {
744                                                 if (!((*srcp)&0xFF000000))
745                                                 {
746                                                         srcp++;
747                                                         dstp++;
748                                                 } else
749                                                 {
750                                                         uint32_t icol = *srcp++;
751 #if BYTE_ORDER == LITTLE_ENDIAN
752                                                         *dstp++ = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
753 #else
754                                                         *dstp++ = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
755 #endif
756                                                 }
757                                         }
758                                 } else
759                                 {
760                                         while (width--)
761                                         {
762                                                 uint32_t icol = *srcp++;
763 #if BYTE_ORDER == LITTLE_ENDIAN
764                                                 *dstp++ = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
765 #else
766                                                 *dstp++ = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
767 #endif
768                                         }
769                                 }
770                                 srcptr+=src.surface->stride;
771                                 dstptr+=surface->stride;
772                         }
773                 }
774                 else
775                         eWarning("[gPixmap] cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp);
776 #ifdef GPIXMAP_DEBUG
777                 s.stop();
778                 eDebug("[gPixmap] [BLITBENCH] cpu blit took %u us", s.elapsed_us());
779 #endif
780         }
781 }
782
783 #undef FIX
784
785 void gPixmap::mergePalette(const gPixmap &target)
786 {
787         if ((!surface->clut.colors) || (!target.surface->clut.colors))
788                 return;
789
790         gColor *lookup=new gColor[surface->clut.colors];
791
792         for (int i=0; i<surface->clut.colors; i++)
793                 lookup[i].color=target.surface->clut.findColor(surface->clut.data[i]);
794
795         delete [] surface->clut.data;
796         surface->clut.colors=target.surface->clut.colors;
797         surface->clut.data=new gRGB[surface->clut.colors];
798         memcpy(surface->clut.data, target.surface->clut.data, sizeof(gRGB)*surface->clut.colors);
799
800         uint8_t *dstptr=(uint8_t*)surface->data;
801
802         for (int ay=0; ay<surface->y; ay++)
803         {
804                 for (int ax=0; ax<surface->x; ax++)
805                         dstptr[ax]=lookup[dstptr[ax]];
806                 dstptr+=surface->stride;
807         }
808
809         delete [] lookup;
810 }
811
812 static inline int sgn(int a)
813 {
814         if (a < 0)
815                 return -1;
816         else if (!a)
817                 return 0;
818         else
819                 return 1;
820 }
821
822 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color)
823 {
824         uint32_t col = color;
825         if (surface->bpp != 8)
826         {
827                 if (surface->clut.data && color < surface->clut.colors)
828                         col = surface->clut.data[color].argb();
829                 else
830                         col = 0x10101*color;
831                 col^=0xFF000000;
832         }
833
834         if (surface->bpp == 16)
835         {
836 #if BYTE_ORDER == LITTLE_ENDIAN
837                 col = bswap_16(((col & 0xFF) >> 3) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF0000) >> 19);
838 #else
839                 col = ((col & 0xFF) >> 3) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF0000) >> 19;
840 #endif
841         }
842         line(clip, start, dst, col);
843 }
844
845 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gRGB color)
846 {
847         uint32_t col;
848         col = color.argb();
849         col^=0xFF000000;
850         line(clip, start, dst, col);
851 }
852
853 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, unsigned int color)
854 {
855         if (clip.rects.empty())
856                 return;
857
858         uint8_t *srf8 = 0;
859         uint16_t *srf16 = 0;
860         uint32_t *srf32 = 0;
861         int stride = surface->stride;
862
863         switch (surface->bpp)
864         {
865                 case 8:
866                         srf8 = (uint8_t*)surface->data;
867                         break;
868                 case 16:
869                         srf16 = (uint16_t*)surface->data;
870                         stride /= 2;
871                         break;
872                 case 32:
873                         srf32 = (uint32_t*)surface->data;
874                         stride /= 4;
875                         break;
876         }
877
878         int xa = start.x(), ya = start.y(), xb = dst.x(), yb = dst.y();
879         int dx, dy, x, y, s1, s2, e, temp, swap, i;
880         dy=abs(yb-ya);
881         dx=abs(xb-xa);
882         s1=sgn(xb-xa);
883         s2=sgn(yb-ya);
884         x=xa;
885         y=ya;
886         if (dy>dx)
887         {
888                 temp=dx;
889                 dx=dy;
890                 dy=temp;
891                 swap=1;
892         } else
893                 swap=0;
894         e = 2*dy-dx;
895
896         int lasthit = 0;
897         for(i=1; i<=dx; i++)
898         {
899                                 /* i don't like this clipping loop, but the only */
900                                 /* other choice i see is to calculate the intersections */
901                                 /* before iterating through the pixels. */
902
903                                 /* one could optimize this because of the ordering */
904                                 /* of the bands. */
905
906                 lasthit = 0;
907                 int a = lasthit;
908
909                         /* if last pixel was invisble, first check bounding box */
910                 if (a == -1)
911                 {
912                                 /* check if we just got into the bbox again */
913                         if (clip.extends.contains(x, y))
914                                 lasthit = a = 0;
915                         else
916                                 goto fail;
917                 } else if (!clip.rects[a].contains(x, y))
918                 {
919                         do
920                         {
921                                 ++a;
922                                 if ((unsigned int)a == clip.rects.size())
923                                         a = 0;
924                                 if (a == lasthit)
925                                 {
926                                         goto fail;
927                                         lasthit = -1;
928                                 }
929                         } while (!clip.rects[a].contains(x, y));
930                         lasthit = a;
931                 }
932
933                 if (srf8)
934                         srf8[y * stride + x] = color;
935                 else if (srf16)
936                         srf16[y * stride + x] = color;
937                 else
938                         srf32[y * stride + x] = color;
939 fail:
940                 while (e>=0)
941                 {
942                         if (swap==1)
943                                 x+=s1;
944                         else
945                                 y+=s2;
946                         e-=2*dx;
947                 }
948
949                 if (swap==1)
950                         y+=s2;
951                 else
952                         x+=s1;
953                 e+=2*dy;
954         }
955 }
956
957 gColor gPalette::findColor(const gRGB rgb) const
958 {
959                 /* grayscale? */
960         if (!data)
961                 return (rgb.r + rgb.g + rgb.b) / 3;
962
963         if (rgb.a == 255) /* Fully transparent, then RGB does not matter */
964         {
965                 for (int t=0; t<colors; t++)
966                         if (data[t].a == 255)
967                                 return t;
968         }
969
970         int difference=1<<30, best_choice=0;
971         for (int t=0; t<colors; t++)
972         {
973                 int ttd;
974                 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
975                 ttd=td;
976                 if (ttd>=difference)
977                         continue;
978                 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
979                 ttd+=td;
980                 if (ttd>=difference)
981                         continue;
982                 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
983                 ttd+=td;
984                 if (ttd>=difference)
985                         continue;
986                 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
987                 ttd+=td;
988                 if (ttd>=difference)
989                         continue;
990                 if (!ttd)
991                         return t;
992                 difference=ttd;
993                 best_choice=t;
994         }
995         return best_choice;
996 }
997
998 DEFINE_REF(gPixmap);
999
1000 gPixmap::~gPixmap()
1001 {
1002         if (on_dispose)
1003                 on_dispose(this);
1004         if (surface)
1005                 delete (gSurface*)surface;
1006 }
1007
1008 static void donot_delete_surface(gPixmap *pixmap)
1009 {
1010         pixmap->surface = NULL;
1011 }
1012
1013 gPixmap::gPixmap(gUnmanagedSurface *surface):
1014         surface(surface),
1015         on_dispose(donot_delete_surface)
1016 {
1017 }
1018
1019 gPixmap::gPixmap(eSize size, int bpp, int accel):
1020         surface(new gSurface(size.width(), size.height(), bpp, accel)),
1021         on_dispose(NULL)
1022 {
1023 }
1024
1025 gPixmap::gPixmap(int width, int height, int bpp, gPixmapDisposeCallback call_on_dispose, int accel):
1026         surface(new gSurface(width, height, bpp, accel)),
1027         on_dispose(call_on_dispose)
1028 {
1029 }