trunk 20080912
[gitenigma.git] / lib / gdi / gpixmap.cpp
bloba449f7c3af61a9932aeeadd78642f684d17a64e0
1 #include <lib/gdi/gpixmap.h>
2 #include <zlib.h>
4 gLookup::gLookup()
5 :size(0), lookup(0)
9 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
10 :size(0), lookup(0)
12 build(size, pal, start, end);
15 void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
17 if (lookup)
19 delete [] lookup;
20 lookup=0;
21 size=0;
23 size=_size;
24 if (!size)
25 return;
26 lookup=new gColor[size];
28 for (int i=0; i<size; i++)
30 gRGB col;
31 if (i)
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);
51 gPixmap *gPixmap::lock()
53 contentlock.lock(1);
54 return this;
57 void gPixmap::unlock()
59 contentlock.unlock(1);
62 void gPixmap::fill(const eRect &area, const gColor &color)
64 if ((area.height()<=0) || (area.width()<=0))
65 return;
66 if (bpp == 8)
67 for (int y=area.top(); y<area.bottom(); y++)
68 memset(((__u8*)data)+y*stride+area.left(), color.color, area.width());
69 else if (bpp == 32)
70 for (int y=area.top(); y<area.bottom(); y++)
72 __u32 *dst=(__u32*)(((__u8*)data)+y*stride+area.left()*bypp);
73 int x=area.width();
74 __u32 col;
76 if (clut.data && color < clut.colors)
77 col=(clut.data[color].a<<24)|(clut.data[color].r<<16)|(clut.data[color].g<<8)|(clut.data[color].b);
78 else
79 col=0x10101*color;
80 col^=0xFF000000;
81 while (x--)
82 *dst++=col;
84 else
85 eWarning("couldn't fill %d bpp", bpp);
88 void gPixmap::blit(const gPixmap &src, ePoint pos, const eRect &clip, int flag)
90 eRect area=eRect(pos, src.getSize());
91 area&=clip;
92 area&=eRect(ePoint(0, 0), getSize());
93 if ((area.width()<0) || (area.height()<0))
94 return;
96 eRect srcarea=area;
97 srcarea.moveBy(-pos.x(), -pos.y());
99 __u8 *srcdata=src.uncompressdatanoreplace();
100 __u8 *srcptr=srcdata;
101 __u8 *dstptr=(__u8*)data;
103 if ((bpp == 8) && (src.bpp==8))
106 srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
107 dstptr+=area.left()*bypp+area.top()*stride;
108 for (int y=0; y<area.height(); y++)
110 if (flag & blitAlphaTest)
112 // no real alphatest yet
113 int width=area.width();
114 unsigned char *src=(unsigned char*)srcptr;
115 unsigned char *dst=(unsigned char*)dstptr;
116 // use duff's device here!
117 while (width--)
119 if (!*src)
121 src++;
122 dst++;
123 } else
124 *dst++=*src++;
126 } else
127 memcpy(dstptr, srcptr, area.width()*bypp);
128 srcptr+=src.stride;
129 dstptr+=stride;
131 } else if ((bpp == 32) && (src.bpp==8))
133 __u32 pal[256];
135 for (int i=0; i<256; ++i)
137 if (src.clut.data && (i<src.clut.colors))
138 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);
139 else
140 pal[i]=0x010101*i;
141 pal[i]^=0xFF000000;
144 srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
145 dstptr+=area.left()*bypp+area.top()*stride;
146 for (int y=0; y<area.height(); y++)
148 if (flag & blitAlphaTest)
150 // no real alphatest yet
151 int width=area.width();
152 unsigned char *src=(unsigned char*)srcptr;
153 __u32 *dst=(__u32*)dstptr;
154 // use duff's device here!
155 while (width--)
157 if (!*src)
159 src++;
160 dst++;
161 } else
162 *dst++=pal[*src++];
164 } else
166 int width=area.width();
167 unsigned char *src=(unsigned char*)srcptr;
168 __u32 *dst=(__u32*)dstptr;
169 while (width--)
170 *dst++=pal[*src++];
172 srcptr+=src.stride;
173 dstptr+=stride;
175 } else
176 eFatal("cannot blit %dbpp from %dbpp", bpp, src.bpp);
177 if (src.compressedsize)
178 delete[] srcdata;
181 void gPixmap::mergePalette(const gPixmap &target)
183 if ((!clut.colors) || (!target.clut.colors))
184 return;
185 gColor *lookup=new gColor[clut.colors];
187 for (int i=0; i<clut.colors; i++)
188 lookup[i].color=target.clut.findColor(clut.data[i]);
190 delete [] clut.data;
191 clut.colors=target.clut.colors;
192 clut.data=new gRGB[clut.colors];
193 memcpy(clut.data, target.clut.data, sizeof(gRGB)*clut.colors);
194 uncompressdata();
195 __u8 *dstptr=(__u8*)data;
197 for (int ay=0; ay<y; ay++)
199 for (int ax=0; ax<x; ax++)
200 dstptr[ax]=lookup[dstptr[ax]];
201 dstptr+=stride;
204 delete [] lookup;
205 compressdata();
207 void gPixmap::compressdata()
209 if (cancompress && !compressedsize)
211 uLongf comprlen = x*y*bypp;
212 if (comprlen > 1000) // only compress "big" images
214 lock();
215 __u8 compressed[comprlen];
216 if (compress2(compressed,&comprlen,(__u8*)data,comprlen,Z_BEST_SPEED) == Z_OK)
218 delete[] (char*)data;
219 data = new __u8[comprlen];
220 memcpy(data,compressed,comprlen);
221 compressedsize=comprlen;
223 unlock();
227 void gPixmap::uncompressdata()
229 if (compressedsize)
231 lock();
232 uLongf uncomprlen = x*y*bypp;
233 __u8* uncompressed = new __u8[uncomprlen];
234 uncompress(uncompressed,&uncomprlen,(__u8*)data,compressedsize);
235 delete[] (char*)data;
236 data = uncompressed;
237 compressedsize = 0;
238 unlock();
241 __u8* gPixmap::uncompressdatanoreplace() const
243 if (compressedsize)
245 uLongf uncomprlen = x*y*bypp;
246 __u8* uncompressed = new __u8[uncomprlen];
247 uncompress(uncompressed,&uncomprlen,(__u8*)data,compressedsize);
248 return uncompressed;
250 return (__u8*)data;
253 void gPixmap::line(ePoint start, ePoint dst, gColor color)
255 int Ax=start.x(), // dieser code rult ganz ganz doll weil er ganz ganz fast ist und auch sehr gut dokumentiert is
256 Ay=start.y(), Bx=dst.x(), // t. es handelt sich immerhin um den weltbekannten bresenham algorithmus der nicht nur
257 By=dst.y(); int dX, dY, fbXincr, // sehr schnell ist sondern auch sehr gut dokumentiert und getestet wurde. nicht
258 fbYincr, fbXYincr, dPr, dPru, P; __u8 // nur auf dem LCD der dbox, sondern auch ueberall anders. und auch auf der
259 *AfbAddr = &((__u8*)data)[Ay*stride+Ax*bypp]; __u8 // dbox mit LCD soll das teil nun tun, und ich denke das tut es. ausse
260 *BfbAddr = &((__u8*)data)[By*stride+Bx*bypp]; fbXincr= // rdem hat dieser algo den vorteil dass man fehler sehr leicht fi
261 bypp; if ( (dX=Bx-Ax) >= 0) goto AFTERNEGX; dX=-dX; // ndet und beheben kann. das liegt nicht zuletzt an den komment
262 fbXincr=-1; AFTERNEGX: fbYincr=stride; if ( (dY=By // aren. und ausserdem, je kuerzer der code, desto weniger k
263 -Ay) >= 0) goto AFTERNEGY; fbYincr=-stride; dY=-dY;AFTERNEGY: // ann daran falsch sein. erwaehnte ich schon, da
264 fbXYincr = fbXincr+fbYincr; if (dY > dX) goto YisIndependent; dPr = dY+ // s dieser tolle code wahnsinnig schnell
265 dY; P = -dX; dPru = P+P; dY = dX>>1; XLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) // ist? bye, tmbinc
266 goto RightAndUp; AfbAddr+=fbXincr; BfbAddr-=fbXincr; if ((dY=dY-1) > 0) goto XLOOP; *AfbAddr=color; if ((dX & 1)
267 == 0) return; *BfbAddr=color; return; RightAndUp: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dY=dY-1) >
268 0) goto XLOOP; *AfbAddr=color; if ((dX & 1) == 0) return; *BfbAddr=color; return; YisIndependent: dPr = dX+dX; P
269 = -dY; dPru = P+P; dX = dY>>1; YLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) goto RightAndUp2; AfbAddr
270 +=fbYincr; BfbAddr-=fbYincr; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr=color; if ((dY & 1) == 0) return; *BfbAddr=
271 color;return; RightAndUp2: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr
272 =color; if((dY & 1) == 0) return; *BfbAddr=color; return; // nun ist der tolle code leider zu ende. tut mir leid.
275 gColor gPalette::findColor(const gRGB &rgb) const
277 int difference=1<<30, best_choice=0;
278 for (int t=0; t<colors; t++)
280 int ttd;
281 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
282 ttd=td;
283 if (ttd>=difference)
284 continue;
285 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
286 ttd+=td;
287 if (ttd>=difference)
288 continue;
289 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
290 ttd+=td;
291 if (ttd>=difference)
292 continue;
293 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
294 ttd+=td;
295 if (ttd>=difference)
296 continue;
297 difference=ttd;
298 best_choice=t;
300 return best_choice;
303 void gPixmap::finalLock()
305 if (!final)
306 contentlock.lock();
307 final=1;
310 gPixmap::gPixmap()
311 :final(0),cancompress(false),compressedsize(0)
315 gPixmap::~gPixmap()
317 finalLock();
318 delete[] clut.data;
321 gImage::gImage(eSize size, int _bpp)
323 x=size.width();
324 y=size.height();
325 bpp=_bpp;
326 switch (bpp)
328 case 8:
329 bypp=1;
330 break;
331 case 15:
332 case 16:
333 bypp=2;
334 break;
335 case 24: // never use 24bit mode
336 case 32:
337 bypp=4;
338 break;
339 default:
340 bypp=(bpp+7)/8;
342 stride=x*bypp;
343 clut.colors=0;
344 clut.data=0;
345 data=new char[x*y*bypp];
346 cancompress = true;
349 gImage::~gImage()
351 finalLock();
352 delete[] (char*)data;