3 #include <lib/gdi/gpixmap.h>
4 #include <lib/gdi/region.h>
5 #include <lib/gdi/accel.h>
14 gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
17 build(size, pal, start, end);
20 void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
31 lookup=new gColor[size];
33 for (int i=0; i<size; i++)
38 int rdiff=-start.r+end.r;
39 int gdiff=-start.g+end.g;
40 int bdiff=-start.b+end.b;
41 int adiff=-start.a+end.a;
42 rdiff*=i; rdiff/=(size-1);
43 gdiff*=i; gdiff/=(size-1);
44 bdiff*=i; bdiff/=(size-1);
45 adiff*=i; adiff/=(size-1);
52 lookup[i]=pal.findColor(col);
70 gSurface::gSurface(eSize size, int _bpp, int accel)
85 case 24: // never use 24bit mode
107 if (gAccel::getInstance())
108 eDebug("accel memory: %d", gAccel::getInstance()->accelAlloc(data, data_phys, y * stride + pal_size));
110 eDebug("no accel available");
117 data = new unsigned char [y * stride];
122 gSurface::~gSurface()
127 gAccel::getInstance()->accelFree(data_phys);
129 delete [] (unsigned char*)data;
135 gPixmap *gPixmap::lock()
141 void gPixmap::unlock()
143 contentlock.unlock(1);
146 void gPixmap::fill(const gRegion ®ion, const gColor &color)
149 for (i=0; i<region.rects.size(); ++i)
151 const eRect &area = region.rects[i];
155 if (surface->bpp == 8)
157 for (int y=area.top(); y<area.bottom(); y++)
158 memset(((__u8*)surface->data)+y*surface->stride+area.left(), color.color, area.width());
159 } else if (surface->bpp == 16)
163 if (surface->clut.data && color < surface->clut.colors)
164 icol=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
168 __u16 col = ((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF) >> 2) << 5 | (icol & 0xFF00) >> 11;
170 __u16 col = ((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF) >> 3;
172 for (int y=area.top(); y<area.bottom(); y++)
174 __u16 *dst=(__u16*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
179 } else if (surface->bpp == 32)
183 if (surface->clut.data && color < surface->clut.colors)
184 col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
190 if (surface->data_phys && gAccel::getInstance())
191 if (!gAccel::getInstance()->fill(surface, area, col))
194 for (int y=area.top(); y<area.bottom(); y++)
196 __u32 *dst=(__u32*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
202 eWarning("couldn't fill %d bpp", surface->bpp);
206 void gPixmap::fill(const gRegion ®ion, const gRGB &color)
209 for (i=0; i<region.rects.size(); ++i)
211 const eRect &area = region.rects[i];
215 if (surface->bpp == 32)
222 if (surface->data_phys && gAccel::getInstance())
223 if (!gAccel::getInstance()->fill(surface, area, col))
226 for (int y=area.top(); y<area.bottom(); y++)
228 __u32 *dst=(__u32*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
233 } else if (surface->bpp == 16)
235 __u32 icol = color.argb();
237 __u16 col = ((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF) >> 2) << 5 | (icol & 0xFF00) >> 11;
239 __u16 col = ((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF) >> 3;
241 for (int y=area.top(); y<area.bottom(); y++)
243 __u16 *dst=(__u16*)(((__u8*)surface->data)+y*surface->stride+area.left()*surface->bypp);
249 eWarning("couldn't rgbfill %d bpp", surface->bpp);
253 static inline void blit_8i_to_32(__u32 *dst, __u8 *src, __u32 *pal, int width)
259 static inline void blit_8i_to_32_at(__u32 *dst, __u8 *src, __u32 *pal, int width)
263 if (!(pal[*src]&0x80000000))
272 static inline void blit_8i_to_16(__u16 *dst, __u8 *src, __u32 *pal, int width)
275 *dst++=pal[*src++] & 0xFFFF;
278 static inline void blit_8i_to_16_at(__u16 *dst, __u8 *src, __u32 *pal, int width)
282 if (!(pal[*src]&0x80000000))
287 *dst++=pal[*src++] & 0xFFFF;
291 /* WARNING, this function is not endian safe! */
292 static void blit_8i_to_32_ab(__u32 *dst, __u8 *src, __u32 *pal, int width)
296 #define BLEND(x, y, a) (y + (((x-y) * a)>>8))
297 __u32 srccol = pal[*src++];
299 unsigned char sb = srccol & 0xFF;
300 unsigned char sg = (srccol >> 8) & 0xFF;
301 unsigned char sr = (srccol >> 16) & 0xFF;
302 unsigned char sa = (srccol >> 24) & 0xFF;
304 unsigned char db = dstcol & 0xFF;
305 unsigned char dg = (dstcol >> 8) & 0xFF;
306 unsigned char dr = (dstcol >> 16) & 0xFF;
307 unsigned char da = (dstcol >> 24) & 0xFF;
309 da = BLEND(0xFF, da, sa) & 0xFF;
310 dr = BLEND(sr, dr, sa) & 0xFF;
311 dg = BLEND(sg, dg, sa) & 0xFF;
312 db = BLEND(sb, db, sa) & 0xFF;
315 *dst++ = db | (dg << 8) | (dr << 16) | (da << 24);
321 void gPixmap::blit(const gPixmap &src, const eRect &_pos, const gRegion &clip, int flag)
323 // eDebug("blit: -> %d.%d %d:%d -> %d.%d %d:%d, flags=%d",
324 // _pos.x(), _pos.y(), _pos.width(), _pos.height(),
325 // clip.extends.x(), clip.extends.y(), clip.extends.width(), clip.extends.height(),
329 // eDebug("source size: %d %d", src.size().width(), src.size().height());
331 if (!(flag & blitScale)) /* pos' size is valid only when scaling */
332 pos = eRect(pos.topLeft(), src.size());
333 else if (pos.size() == src.size()) /* no scaling required */
336 int scale_x = FIX, scale_y = FIX;
338 if (flag & blitScale)
340 ASSERT(src.size().width());
341 ASSERT(src.size().height());
342 scale_x = pos.size().width() * FIX / src.size().width();
343 scale_y = pos.size().height() * FIX / src.size().height();
346 // eDebug("SCALE %x %x", scale_x, scale_y);
348 for (unsigned int i=0; i<clip.rects.size(); ++i)
350 // eDebug("clip rect: %d %d %d %d", clip.rects[i].x(), clip.rects[i].y(), clip.rects[i].width(), clip.rects[i].height());
351 eRect area = pos; /* pos is the virtual (pre-clipping) area on the dest, which can be larger/smaller than src if scaling is enabled */
353 area&=eRect(ePoint(0, 0), size());
358 eRect srcarea = area;
359 srcarea.moveBy(-pos.x(), -pos.y());
361 // eDebug("srcarea before scale: %d %d %d %d",
362 // srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
364 if (flag & blitScale)
365 srcarea = eRect(srcarea.x() * FIX / scale_x, srcarea.y() * FIX / scale_y, srcarea.width() * FIX / scale_x, srcarea.height() * FIX / scale_y);
367 // eDebug("srcarea after scale: %d %d %d %d",
368 // srcarea.x(), srcarea.y(), srcarea.width(), srcarea.height());
370 if ((surface->data_phys && src.surface->data_phys) && (gAccel::getInstance()))
371 if (!gAccel::getInstance()->blit(surface, src.surface, area, srcarea, flag))
374 if (flag & blitScale)
376 eWarning("unimplemented: scale on non-accel surfaces");
380 if ((surface->bpp == 8) && (src.surface->bpp==8))
382 __u8 *srcptr=(__u8*)src.surface->data;
383 __u8 *dstptr=(__u8*)surface->data;
385 srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
386 dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
387 for (int y=0; y<area.height(); y++)
389 if (flag & (blitAlphaTest|blitAlphaBlend))
391 // no real alphatest yet
392 int width=area.width();
393 unsigned char *src=(unsigned char*)srcptr;
394 unsigned char *dst=(unsigned char*)dstptr;
395 // use duff's device here!
406 memcpy(dstptr, srcptr, area.width()*surface->bypp);
407 srcptr+=src.surface->stride;
408 dstptr+=surface->stride;
410 } else if ((surface->bpp == 32) && (src.surface->bpp==32))
412 __u32 *srcptr=(__u32*)src.surface->data;
413 __u32 *dstptr=(__u32*)surface->data;
415 srcptr+=srcarea.left()+srcarea.top()*src.surface->stride/4;
416 dstptr+=area.left()+area.top()*surface->stride/4;
417 for (int y=0; y<area.height(); y++)
419 if (flag & blitAlphaTest)
421 int width=area.width();
422 unsigned long *src=(unsigned long*)srcptr;
423 unsigned long *dst=(unsigned long*)dstptr;
427 if (!((*src)&0xFF000000))
434 } else if (flag & blitAlphaBlend)
436 // uh oh. this is only until hardware accel is working.
438 int width=area.width();
440 unsigned char *src=(unsigned char*)srcptr;
441 unsigned char *dst=(unsigned char*)dstptr;
443 #define BLEND(x, y, a) (y + ((x-y) * a)/256)
446 unsigned char sa = src[3];
447 unsigned char sr = src[2];
448 unsigned char sg = src[1];
449 unsigned char sb = src[0];
451 unsigned char da = dst[3];
452 unsigned char dr = dst[2];
453 unsigned char dg = dst[1];
454 unsigned char db = dst[0];
456 dst[3] = BLEND(0xFF, da, sa);
457 dst[2] = BLEND(sr, dr, sa);
458 dst[1] = BLEND(sg, dg, sa);
459 dst[0] = BLEND(sb, db, sa);
465 memcpy(dstptr, srcptr, area.width()*surface->bypp);
466 srcptr+=src.surface->stride/4;
467 dstptr+=surface->stride/4;
469 } else if ((surface->bpp == 32) && (src.surface->bpp==8))
471 __u8 *srcptr=(__u8*)src.surface->data;
472 __u8 *dstptr=(__u8*)surface->data; // !!
475 for (int i=0; i<256; ++i)
477 if (src.surface->clut.data && (i<src.surface->clut.colors))
478 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);
484 srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
485 dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
486 for (int y=0; y<area.height(); y++)
488 int width=area.width();
489 unsigned char *psrc=(unsigned char*)srcptr;
490 __u32 *dst=(__u32*)dstptr;
491 if (flag & blitAlphaTest)
492 blit_8i_to_32_at(dst, psrc, pal, width);
493 else if (flag & blitAlphaBlend)
494 blit_8i_to_32_ab(dst, psrc, pal, width);
496 blit_8i_to_32(dst, psrc, pal, width);
497 srcptr+=src.surface->stride;
498 dstptr+=surface->stride;
500 } else if ((surface->bpp == 16) && (src.surface->bpp==8))
502 __u8 *srcptr=(__u8*)src.surface->data;
503 __u8 *dstptr=(__u8*)surface->data; // !!
506 for (int i=0; i<256; ++i)
509 if (src.surface->clut.data && (i<src.surface->clut.colors))
510 icol=(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);
514 pal[i]=icol&0xFF000000 | ((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF) >> 2) << 5 | (icol & 0xFF00) >> 11;
516 pal[i]=icol&0xFF000000 | ((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF) >> 3;
521 srcptr+=srcarea.left()*src.surface->bypp+srcarea.top()*src.surface->stride;
522 dstptr+=area.left()*surface->bypp+area.top()*surface->stride;
524 if (flag & blitAlphaBlend)
525 eWarning("ignore unsupported 8bpp -> 16bpp alphablend!");
527 for (int y=0; y<area.height(); y++)
529 int width=area.width();
530 unsigned char *psrc=(unsigned char*)srcptr;
531 __u16 *dst=(__u16*)dstptr;
532 if (flag & blitAlphaTest)
533 blit_8i_to_16_at(dst, psrc, pal, width);
535 blit_8i_to_16(dst, psrc, pal, width);
536 srcptr+=src.surface->stride;
537 dstptr+=surface->stride;
539 } else if ((surface->bpp == 16) && (src.surface->bpp==32))
541 __u8 *srcptr=(__u8*)src.surface->data;
542 __u8 *dstptr=(__u8*)surface->data;
544 srcptr+=srcarea.left()+srcarea.top()*src.surface->stride;
545 dstptr+=area.left()+area.top()*surface->stride;
547 if (flag & blitAlphaBlend)
548 eWarning("ignore unsupported 32bpp -> 16bpp alphablend!");
550 for (int y=0; y<area.height(); y++)
552 int width=area.width();
553 __u32 *srcp=(__u32*)srcptr;
554 __u16 *dstp=(__u16*)dstptr;
556 if (flag & blitAlphaTest)
560 if (!((*srcp)&0xFF000000))
566 __u32 icol = *srcp++;
568 *dstp++=((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF) >> 2) << 5 | (icol & 0xFF00) >> 11;
570 *dstp++=((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF) >> 3;
578 __u32 icol = *srcp++;
580 *dstp++=((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF) >> 2) << 5 | (icol & 0xFF00) >> 11;
582 *dstp++=((icol & 0xFF0000) >> 19) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF) >> 3;
586 srcptr+=src.surface->stride;
587 dstptr+=surface->stride;
590 eWarning("cannot blit %dbpp from %dbpp", surface->bpp, src.surface->bpp);
596 void gPixmap::mergePalette(const gPixmap &target)
598 if ((!surface->clut.colors) || (!target.surface->clut.colors))
601 gColor *lookup=new gColor[surface->clut.colors];
603 for (int i=0; i<surface->clut.colors; i++)
604 lookup[i].color=target.surface->clut.findColor(surface->clut.data[i]);
606 delete [] surface->clut.data;
607 surface->clut.colors=target.surface->clut.colors;
608 surface->clut.data=new gRGB[surface->clut.colors];
609 memcpy(surface->clut.data, target.surface->clut.data, sizeof(gRGB)*surface->clut.colors);
611 __u8 *dstptr=(__u8*)surface->data;
613 for (int ay=0; ay<surface->y; ay++)
615 for (int ax=0; ax<surface->x; ax++)
616 dstptr[ax]=lookup[dstptr[ax]];
617 dstptr+=surface->stride;
623 static inline int sgn(int a)
633 void gPixmap::line(const gRegion &clip, ePoint start, ePoint dst, gColor color)
638 int stride = surface->stride;
640 if (clip.rects.empty())
645 if (surface->bpp == 8)
646 srf8 = (__u8*)surface->data;
649 srf32 = (__u32*)surface->data;
650 if (surface->clut.data && color < surface->clut.colors)
651 col=(surface->clut.data[color].a<<24)|(surface->clut.data[color].r<<16)|(surface->clut.data[color].g<<8)|(surface->clut.data[color].b);
657 if (surface->bpp == 16)
660 col16=((col & 0xFF0000) >> 19) << 11 | ((col & 0xFF) >> 2) << 5 | (col & 0xFF00) >> 11;
662 col16=((col & 0xFF0000) >> 19) << 11 | ((col & 0xFF00) >> 10) << 5 | (col & 0xFF) >> 3;
666 int xa = start.x(), ya = start.y(), xb = dst.x(), yb = dst.y();
667 int dx, dy, x, y, s1, s2, e, temp, swap, i;
687 /* i don't like this clipping loop, but the only */
688 /* other choice i see is to calculate the intersections */
689 /* before iterating through the pixels. */
691 /* one could optimize this because of the ordering */
697 /* if last pixel was invisble, first check bounding box */
700 /* check if we just got into the bbox again */
701 if (clip.extends.contains(x, y))
705 } else if (!clip.rects[a].contains(x, y))
710 if ((unsigned int)a == clip.rects.size())
717 } while (!clip.rects[a].contains(x, y));
722 srf8[y * stride + x] = color;
724 srf16[y * stride/2 + x] = col16;
726 srf32[y * stride/4 + x] = col;
745 gColor gPalette::findColor(const gRGB &rgb) const
749 return (rgb.r + rgb.g + rgb.b) / 3;
751 int difference=1<<30, best_choice=0;
752 for (int t=0; t<colors; t++)
755 int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
759 td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
763 td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
767 td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
783 if (must_delete_surface)
787 gPixmap::gPixmap(gSurface *surface)
788 :surface(surface), must_delete_surface(false)
792 gPixmap::gPixmap(eSize size, int bpp, int accel)
793 :must_delete_surface(true)
795 surface = new gSurface(size, bpp, accel);