import of enigma2
[enigma2.git] / lib / gdi / gpixmap.cpp
1 #include <lib/gdi/gpixmap.h>
2
3 gLookup::gLookup()
4 {
5         size=0;
6         lookup=0;
7 }
8
9 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
10 {
11         size=0;
12         lookup=0;
13         build(size, pal, start, end);
14 }
15
16 void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
17 {
18         if (lookup)
19         {
20                 delete lookup;
21                 lookup=0;
22                 size=0;
23         }
24         size=_size;
25         if (!size)
26                 return;
27         lookup=new gColor[size];
28         
29         for (int i=0; i<size; i++)
30         {
31                 gRGB col;
32                 if (i)
33                 {
34                         int rdiff=-start.r+end.r;
35                         int gdiff=-start.g+end.g;
36                         int bdiff=-start.b+end.b;
37                         int adiff=-start.a+end.a;
38                         rdiff*=i; rdiff/=(size-1);
39                         gdiff*=i; gdiff/=(size-1);
40                         bdiff*=i; bdiff/=(size-1);
41                         adiff*=i; adiff/=(size-1);
42                         col.r=start.r+rdiff;
43                         col.g=start.g+gdiff;
44                         col.b=start.b+bdiff;
45                         col.a=start.a+adiff;
46                 } else
47                         col=start;
48                 lookup[i]=pal.findColor(col);
49         }
50 }
51
52 DEFINE_REF(gPixmap);
53
54 void gPixmap::fill(const eRect &area, const gColor &color)
55 {
56         if ((area.height()<=0) || (area.width()<=0))
57                 return;
58         if (bpp == 8)
59                 for (int y=area.top(); y<area.bottom(); y++)
60                         memset(((__u8*)data)+y*stride+area.left(), color.color, area.width());
61         else if (bpp == 32)
62                 for (int y=area.top(); y<area.bottom(); y++)
63                 {
64                         __u32 *dst=(__u32*)(((__u8*)data)+y*stride+area.left()*bypp);
65                         int x=area.width();
66                         __u32 col;
67
68                         if (clut.data && color < clut.colors)
69                                 col=(clut.data[color].a<<24)|(clut.data[color].r<<16)|(clut.data[color].g<<8)|(clut.data[color].b);
70                         else
71                                 col=0x10101*color;
72                         col^=0xFF000000;                        
73                         while (x--)
74                                 *dst++=col;
75                 }
76         else
77                 eWarning("couldn't fill %d bpp", bpp);
78 }
79
80 void gPixmap::blit(const gPixmap &src, ePoint pos, const eRect &clip, int flag)
81 {
82         
83         eRect area=eRect(pos, src.getSize());
84         if (!clip.isNull())
85                 area&=clip;
86         area&=eRect(ePoint(0, 0), getSize());
87         if ((area.width()<0) || (area.height()<0))
88                 return;
89         
90         eRect srcarea=area;
91         srcarea.moveBy(-pos.x(), -pos.y());
92
93         if ((bpp == 8) && (src.bpp==8))
94         {
95                 __u8 *srcptr=(__u8*)src.data;
96                 __u8 *dstptr=(__u8*)data;
97         
98                 srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
99                 dstptr+=area.left()*bypp+area.top()*stride;
100                 for (int y=0; y<area.height(); y++)
101                 {
102                         if (flag & blitAlphaTest)
103                         {
104               // no real alphatest yet
105                                 int width=area.width();
106                                 unsigned char *src=(unsigned char*)srcptr;
107                                 unsigned char *dst=(unsigned char*)dstptr;
108                                         // use duff's device here!
109                                 while (width--)
110                                 {
111                                         if (!*src)
112                                         {
113                                                 src++;
114                                                 dst++;
115                                         } else
116                                                 *dst++=*src++;
117                                 }
118                         } else
119                                 memcpy(dstptr, srcptr, area.width()*bypp);
120                         srcptr+=src.stride;
121                         dstptr+=stride;
122                 }
123         } else if ((bpp == 32) && (src.bpp==8))
124         {
125                 __u8 *srcptr=(__u8*)src.data;
126                 __u8 *dstptr=(__u8*)data; // !!
127                 __u32 pal[256];
128                 
129                 for (int i=0; i<256; ++i)
130                 {
131                         if (src.clut.data && (i<src.clut.colors))
132                                 pal[i]=(src.clut.data[i].a<<24)|(src.clut.data[i].r<<16)|(src.clut.data[i].g<<8)|(src.clut.data[i].b);
133                         else
134                                 pal[i]=0x010101*i;
135                         pal[i]^=0xFF000000;
136                 }
137         
138                 srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
139                 dstptr+=area.left()*bypp+area.top()*stride;
140                 for (int y=0; y<area.height(); y++)
141                 {
142                         if (flag & blitAlphaTest)
143                         {
144               // no real alphatest yet
145                                 int width=area.width();
146                                 unsigned char *src=(unsigned char*)srcptr;
147                                 __u32 *dst=(__u32*)dstptr;
148                                         // use duff's device here!
149                                 while (width--)
150                                 {
151                                         if (!*src)
152                                         {
153                                                 src++;
154                                                 dst++;
155                                         } else
156                                                 *dst++=pal[*src++];
157                                 }
158                         } else
159                         {
160                                 int width=area.width();
161                                 unsigned char *src=(unsigned char*)srcptr;
162                                 __u32 *dst=(__u32*)dstptr;
163                                 while (width--)
164                                         *dst++=pal[*src++];
165                         }
166                         srcptr+=src.stride;
167                         dstptr+=stride;
168                 }
169         } else
170                 eFatal("cannot blit %dbpp from %dbpp", bpp, src.bpp);
171 }
172
173 void gPixmap::mergePalette(const gPixmap &target)
174 {
175         if ((!clut.colors) || (!target.clut.colors))
176                 return;
177         gColor *lookup=new gColor[clut.colors];
178
179         for (int i=0; i<clut.colors; i++)
180                 lookup[i].color=target.clut.findColor(clut.data[i]);
181         
182         delete clut.data;
183         clut.colors=target.clut.colors;
184         clut.data=new gRGB[clut.colors];
185         memcpy(clut.data, target.clut.data, sizeof(gRGB)*clut.colors);
186
187         __u8 *dstptr=(__u8*)data;
188
189         for (int ay=0; ay<y; ay++)
190         {
191                 for (int ax=0; ax<x; ax++)
192                         dstptr[ax]=lookup[dstptr[ax]];
193                 dstptr+=stride;
194         }
195         
196         delete lookup;  
197 }
198
199 void gPixmap::line(ePoint start, ePoint dst, gColor color)
200 {
201 int Ax=start.x(), // dieser code rult ganz ganz doll weil er ganz ganz fast ist und auch sehr gut dokumentiert is
202 Ay=start.y(), Bx=dst.x(), // t. es handelt sich immerhin um den weltbekannten bresenham algorithmus der nicht nur
203 By=dst.y(); int dX, dY, fbXincr, // sehr schnell ist sondern auch sehr gut dokumentiert und getestet wurde. nicht
204 fbYincr, fbXYincr, dPr, dPru, P; __u8 // nur auf dem LCD der dbox, sondern auch ueberall anders. und auch auf der
205 *AfbAddr = &((__u8*)data)[Ay*stride+Ax*bypp]; __u8 // dbox mit LCD soll das teil nun tun, und ich denke das tut es. ausse
206 *BfbAddr = &((__u8*)data)[By*stride+Bx*bypp]; fbXincr= // rdem hat dieser algo den vorteil dass man fehler sehr leicht fi
207 bypp; if ( (dX=Bx-Ax) >= 0) goto AFTERNEGX; dX=-dX; // ndet und beheben kann. das liegt nicht zuletzt an den komment
208 fbXincr=-1; AFTERNEGX: fbYincr=stride; if ( (dY=By // aren. und ausserdem, je kuerzer der code, desto weniger k
209 -Ay) >= 0) goto AFTERNEGY; fbYincr=-stride; dY=-dY;AFTERNEGY: // ann daran falsch sein. erwaehnte ich schon, da
210 fbXYincr = fbXincr+fbYincr; if (dY > dX) goto YisIndependent; dPr = dY+ // s dieser tolle code wahnsinnig schnell
211 dY; P = -dX; dPru = P+P; dY = dX>>1; XLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) // ist? bye, tmbinc
212 goto RightAndUp;  AfbAddr+=fbXincr; BfbAddr-=fbXincr; if ((dY=dY-1) > 0) goto XLOOP; *AfbAddr=color; if ((dX & 1)
213 == 0) return;  *BfbAddr=color; return; RightAndUp: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dY=dY-1) >
214 0) goto XLOOP;  *AfbAddr=color; if ((dX & 1) == 0) return; *BfbAddr=color; return; YisIndependent: dPr = dX+dX; P
215 = -dY; dPru = P+P; dX = dY>>1; YLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) goto RightAndUp2; AfbAddr
216 +=fbYincr;  BfbAddr-=fbYincr; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr=color; if ((dY & 1) == 0) return; *BfbAddr=
217 color;return; RightAndUp2: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr
218 =color; if((dY & 1) == 0) return; *BfbAddr=color; return; // nun ist der tolle code leider zu ende. tut mir leid.
219 }
220
221 gColor gPalette::findColor(const gRGB &rgb) const
222 {
223         int difference=1<<30, best_choice=0;
224         for (int t=0; t<colors; t++)
225         {
226                 int ttd;
227                 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
228                 ttd=td;
229                 if (ttd>=difference)
230                         continue;
231                 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
232                 ttd+=td;
233                 if (ttd>=difference)
234                         continue;
235                 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
236                 ttd+=td;
237                 if (ttd>=difference)
238                         continue;
239                 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
240                 ttd+=td;
241                 if (ttd>=difference)
242                         continue;
243                 difference=ttd;
244                 best_choice=t;
245         }
246         return best_choice;
247 }
248
249 gPixmap::gPixmap()
250 {
251 }
252
253 gPixmap::~gPixmap()
254 {
255 }
256
257 gImage::gImage(eSize size, int _bpp)
258 {
259         x=size.width();
260         y=size.height();
261         bpp=_bpp;
262         switch (bpp)
263         {
264         case 8:
265                 bypp=1;
266                 break;
267         case 15:
268         case 16:
269                 bypp=2;
270                 break;
271         case 24:                // never use 24bit mode
272         case 32:
273                 bypp=4;
274                 break;
275         default:
276                 bypp=(bpp+7)/8;
277         }
278         stride=x*bypp;
279         if (bpp==8)
280         {
281                 clut.colors=256;
282                 clut.data=new gRGB[clut.colors];
283         } else
284         {
285                 clut.colors=0;
286                 clut.data=0;
287         }
288         data=new char[x*y*bypp];
289 }
290
291 gImage::~gImage()
292 {
293         delete[] clut.data;
294         delete[] (char*)data;
295 }