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