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