forgotten sdl-fix
[enigma2.git] / lib / gdi / gpixmap.cpp
1 #include <lib/gdi/gpixmap.h>
2 #include <lib/gdi/region.h>
3
4 gLookup::gLookup()
5         :size(0), lookup(0)
6 {
7 }
8
9 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
10         :size(0), lookup(0)
11 {
12         build(size, pal, start, end);
13 }
14
15 void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
16 {
17         if (lookup)
18         {
19                 delete [] lookup;
20                 lookup=0;
21                 size=0;
22         }
23         size=_size;
24         if (!size)
25                 return;
26         lookup=new gColor[size];
27         
28         for (int i=0; i<size; i++)
29         {
30                 gRGB col;
31                 if (i)
32                 {
33                         int rdiff=-start.r+end.r;
34                         int gdiff=-start.g+end.g;
35                         int bdiff=-start.b+end.b;
36                         int adiff=-start.a+end.a;
37                         rdiff*=i; rdiff/=(size-1);
38                         gdiff*=i; gdiff/=(size-1);
39                         bdiff*=i; bdiff/=(size-1);
40                         adiff*=i; adiff/=(size-1);
41                         col.r=start.r+rdiff;
42                         col.g=start.g+gdiff;
43                         col.b=start.b+bdiff;
44                         col.a=start.a+adiff;
45                 } else
46                         col=start;
47                 lookup[i]=pal.findColor(col);
48         }
49 }
50
51 gSurface::~gSurface()
52 {
53 }
54
55 gSurfaceSystem::gSurfaceSystem(eSize size, int _bpp)
56 {
57         x=size.width();
58         y=size.height();
59         bpp=_bpp;
60         switch (bpp)
61         {
62         case 8:
63                 bypp=1;
64                 break;
65         case 15:
66         case 16:
67                 bypp=2;
68                 break;
69         case 24:                // never use 24bit mode
70         case 32:
71                 bypp=4;
72                 break;
73         default:
74                 bypp=(bpp+7)/8;
75         }
76         stride=x*bypp;
77         clut.colors=0;
78         clut.data=0;
79         data=malloc(x*y*bypp);
80 }
81
82 gSurfaceSystem::~gSurfaceSystem()
83 {
84         free(data);
85         delete[] clut.data;
86 }
87
88 gPixmap *gPixmap::lock()
89 {
90         contentlock.lock(1);
91         return this;
92 }
93
94 void gPixmap::unlock()
95 {
96         contentlock.unlock(1);
97 }
98
99 void gPixmap::fill(const gRegion &region, const gColor &color)
100 {
101         unsigned int i;
102         for (i=0; i<region.rects.size(); ++i)
103         {
104                 const eRect &area = region.rects[i];
105                 if ((area.height()<=0) || (area.width()<=0))
106                         continue;
107                 if (surface->bpp == 8)
108                 {
109                         for (int y=area.top(); y<area.bottom(); y++)
110                                 memset(((__u8*)surface->data)+y*surface->stride+area.left(), color.color, area.width());
111                 } else if (surface->bpp == 32)
112                         for (int y=area.top(); y<area.bottom(); y++)
113                         {
114                                 __u32 *dst=(__u32*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
115                                 int x=area.width();
116                                 __u32 col;
117
118                                 if (surface->clut.data && color < surface->clut.colors)
119                                         col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
120                                 else
121                                         col=0x10101*color;
122                                 col^=0xFF000000;                        
123                                 while (x--)
124                                         *dst++=col;
125                         }
126                 else
127                         eWarning("couldn't fill %d bpp", surface->bpp);
128         }
129 }
130
131 void gPixmap::blit(const gPixmap &src, ePoint pos, const gRegion &clip, int flag)
132 {
133         for (unsigned int i=0; i<clip.rects.size(); ++i)
134         {
135                 eRect area=eRect(pos, src.size());
136                 area&=clip.rects[i];
137                 area&=eRect(ePoint(0, 0), size());
138                 if ((area.width()<0) || (area.height()<0))
139                         continue;
140
141                 eRect srcarea=area;
142                 srcarea.moveBy(-pos.x(), -pos.y());
143                 
144                 if ((surface->bpp == 8) && (src.surface->bpp==8))
145                 {
146                         __u8 *srcptr=(__u8*)src.surface->data;
147                         __u8 *dstptr=(__u8*)surface->data;
148         
149                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
150                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
151                         for (int y=0; y<area.height(); y++)
152                         {
153                                 if (flag & blitAlphaTest)
154                                 {
155                       // no real alphatest yet
156                                         int width=area.width();
157                                         unsigned char *src=(unsigned char*)srcptr;
158                                         unsigned char *dst=(unsigned char*)dstptr;
159                                                 // use duff's device here!
160                                         while (width--)
161                                         {
162                                                 if (!*src)
163                                                 {
164                                                         src++;
165                                                         dst++;
166                                                 } else
167                                                         *dst++=*src++;
168                                         }
169                                 } else
170                                         memcpy(dstptr, srcptr, area.width()*surface->bypp);
171                                 srcptr+=src.surface->stride;
172                                 dstptr+=surface->stride;
173                         }
174                 } else if ((surface->bpp == 32) && (src.surface->bpp==8))
175                 {       
176                         __u8 *srcptr=(__u8*)src.surface->data;
177                         __u8 *dstptr=(__u8*)surface->data; // !!
178                         __u32 pal[256];
179
180                         for (int i=0; i<256; ++i)
181                         {
182                                 if (src.surface->clut.data && (i<src.surface->clut.colors))
183                                         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);
184                                 else
185                                         pal[i]=0x010101*i;
186                                 pal[i]^=0xFF000000;
187                         }
188         
189                         srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
190                         dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
191                         for (int y=0; y<area.height(); y++)
192                         {
193                                 if (flag & blitAlphaTest)
194                                 {
195                       // no real alphatest yet
196                                         int width=area.width();
197                                         unsigned char *src=(unsigned char*)srcptr;
198                                         __u32 *dst=(__u32*)dstptr;
199                                                 // use duff's device here!
200                                         while (width--)
201                                         {
202                                                 if (!*src)
203                                                 {
204                                                         src++;
205                                                         dst++;
206                                                 } else
207                                                         *dst++=pal[*src++];
208                                         }
209                                 } else
210                                 {
211                                         int width=area.width();
212                                         unsigned char *src=(unsigned char*)srcptr;
213                                         __u32 *dst=(__u32*)dstptr;
214                                         while (width--)
215                                                 *dst++=pal[*src++];
216                                 }
217                                 srcptr+=src.surface->stride;
218                                 dstptr+=surface->stride;
219                         }
220                 } else
221                         eFatal("cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp);
222         }
223 }
224
225 void gPixmap::mergePalette(const gPixmap &target)
226 {
227         if ((!surface->clut.colors) || (!target.surface->clut.colors))
228                 return;
229
230         gColor *lookup=new gColor[surface->clut.colors];
231
232         for (int i=0; i<surface->clut.colors; i++)
233                 lookup[i].color=target.surface->clut.findColor(surface->clut.data[i]);
234         
235         delete [] surface->clut.data;
236         surface->clut.colors=target.surface->clut.colors;
237         surface->clut.data=new gRGB[surface->clut.colors];
238         memcpy(surface->clut.data, target.surface->clut.data, sizeof(gRGB)*surface->clut.colors);
239
240         __u8 *dstptr=(__u8*)surface->data;
241
242         for (int ay=0; ay<surface->y; ay++)
243         {
244                 for (int ax=0; ax<surface->x; ax++)
245                         dstptr[ax]=lookup[dstptr[ax]];
246                 dstptr+=surface->stride;
247         }
248         
249         delete [] lookup;
250 }
251
252 static inline int sgn(int a)
253 {
254         if (a < 0)
255                 return -1;
256         else if (!a)
257                 return 0;
258         else
259                 return 1;
260 }
261
262 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color)
263 {
264         __u8 *srf8 = 0;
265         __u32 *srf32 = 0; 
266         int stride = surface->stride;
267         
268         if (clip.rects.empty())
269                 return;
270                 
271         __u32 col;
272         if (surface->bpp == 8)
273         {
274                 srf8 = (__u8*)surface->data;
275         } else if (surface->bpp == 32)
276         {
277                 srf32 = (__u32*)surface->data;
278                 
279                 if (surface->clut.data && color < surface->clut.colors)
280                         col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
281                 else
282                         col=0x10101*color;
283                 col^=0xFF000000;                        
284         }
285         
286         int xa = start.x(), ya = start.y(), xb = dst.x(), yb = dst.y();
287         int dx, dy, x, y, s1, s2, e, temp, swap, i;
288         dy=abs(yb-ya);
289         dx=abs(xb-xa);
290         s1=sgn(xb-xa);
291         s2=sgn(yb-ya);
292         x=xa;
293         y=ya;
294         if (dy>dx)
295         {
296                 temp=dx;
297                 dx=dy;
298                 dy=temp;
299                 swap=1;
300         } else
301                 swap=0;
302         e = 2*dy-dx;
303         
304         int lasthit = 0;
305         for(i=1; i<=dx; i++)
306         {
307                                 /* i don't like this clipping loop, but the only */
308                                 /* other choice i see is to calculate the intersections */
309                                 /* before iterating through the pixels. */
310                                 
311                                 /* one could optimize this because of the ordering */
312                                 /* of the bands. */
313                                 
314                 lasthit = 0;
315                 int a = lasthit;
316                 
317                         /* if last pixel was invisble, first check bounding box */
318                 if (a == -1)
319                 {
320                                 /* check if we just got into the bbox again */
321                         if (clip.extends.contains(x, y))
322                                 lasthit = a = 0;
323                         else
324                                 goto fail;
325                 } else if (!clip.rects[a].contains(x, y))
326                 {
327                         do
328                         {
329                                 ++a;
330                                 if (a == clip.rects.size())
331                                         a = 0;
332                                 if (a == lasthit)
333                                 {
334                                         goto fail;
335                                         lasthit = -1;
336                                 }
337                         } while (!clip.rects[a].contains(x, y));
338                         lasthit = a;
339                 }
340                 
341                 if (srf8)
342                         srf8[y * stride + x] = color;
343                 if (srf32)
344                         srf32[y * stride/4 + x] = col;
345 fail:
346                 while (e>=0)
347                 {
348                         if (swap==1) x+=s1;
349                         else y+=s2;
350                         e-=2*dx;
351                 }
352     if (swap==1)
353         y+=s2;
354                 else
355                         x+=s1;
356                 e+=2*dy;
357         }
358 }
359
360 gColor gPalette::findColor(const gRGB &rgb) const
361 {
362         int difference=1<<30, best_choice=0;
363         for (int t=0; t<colors; t++)
364         {
365                 int ttd;
366                 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
367                 ttd=td;
368                 if (ttd>=difference)
369                         continue;
370                 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
371                 ttd+=td;
372                 if (ttd>=difference)
373                         continue;
374                 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
375                 ttd+=td;
376                 if (ttd>=difference)
377                         continue;
378                 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
379                 ttd+=td;
380                 if (ttd>=difference)
381                         continue;
382                 if (!ttd)
383                         return t;
384                 difference=ttd;
385                 best_choice=t;
386         }
387         return best_choice;
388 }
389
390 DEFINE_REF(gPixmap);
391
392 gPixmap::~gPixmap()
393 {
394 }
395
396 gPixmap::gPixmap(gSurface *surface): surface(surface)
397 {
398 }
399
400 gPixmap::gPixmap(eSize size, int bpp)
401 {
402         surface = new gSurfaceSystem(size, bpp);
403 }
404