diff options
author | rodri <rgl@antares-labs.eu> | 2024-09-11 20:48:13 +0000 |
---|---|---|
committer | rodri <rgl@antares-labs.eu> | 2024-09-11 20:48:13 +0000 |
commit | 09ffa3cfc72a10e82c5c68f4010d1c518f0c3328 (patch) | |
tree | be398761d4f406071417a0b021803d494aa90c11 /fb.c | |
parent | 8806aad87f7be2d2e82c7db2b9f0978246e5a747 (diff) | |
download | libgraphics-09ffa3cfc72a10e82c5c68f4010d1c518f0c3328.tar.gz libgraphics-09ffa3cfc72a10e82c5c68f4010d1c518f0c3328.tar.bz2 libgraphics-09ffa3cfc72a10e82c5c68f4010d1c518f0c3328.zip |
change the raster format to RGBA32. draw to any image format. clean up.
got rid of the bullshit dance between XRGB32 and RGBA32, now
all rasters are RGBA32 and premultiply alpha before loading
up an image and drawing over the destination. this lets the
user compose their own scenes with correct transparency.
no more mediocre clearcolor.
as a consequence drawing got slower, but if i get the turbo
drawing pool working properly that should go away.
textures also take alpha pre-multiplied channels into account,
dividing them when sampling, so loading transparent textures
will show the correct colors.
Diffstat (limited to 'fb.c')
-rw-r--r-- | fb.c | 102 |
1 files changed, 88 insertions, 14 deletions
@@ -95,6 +95,23 @@ rasterconvF2C(Raster *dst, Raster *src) } static void +premulalpha(Raster *r) +{ + Color c; + ulong *p, len; + + len = Dx(r->r)*Dy(r->r); + p = r->data; + while(len--){ + c = ul2col(*p); + c.r *= c.a; + c.g *= c.a; + c.b *= c.a; + *p++ = col2ul(c); + } +} + +static void fb_createraster(Framebuf *fb, char *name, ulong chan) { Raster *r; @@ -135,11 +152,15 @@ upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter) void (*filterfn)(ulong*, Raster*, Point); Rectangle blkr; Point sp, dp; + Image *tmp; ulong *blk; filterfn = nil; blk = emalloc(scale.x*scale.y*4); blkr = Rect(0,0,scale.x,scale.y); + tmp = allocimage(display, dst->r, RGBA32, 0, DNofill); + if(tmp == nil) + sysfatal("allocimage: %r"); switch(filter){ case UFScale2x: @@ -158,8 +179,10 @@ upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter) filterfn(blk, fb, sp); else memsetl(blk, getpixel(fb, sp), scale.x*scale.y); - loadimage(dst, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4); + loadimage(tmp, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4); } + draw(dst, dst->r, tmp, nil, tmp->r.min); + freeimage(tmp); free(blk); } @@ -186,6 +209,7 @@ framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scal Framebuf *fb; Raster *r, *r2; Rectangle sr, dr; + Image *tmp; qlock(ctl); fb = ctl->getfb(ctl); @@ -203,10 +227,18 @@ framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scal r = r2; } + /* this means the raster is a color one, so duplicate it */ + if(r2 == nil){ + r2 = allocraster(nil, r->r, COLOR32); + memmove(r2->data, r->data, Dx(r->r)*Dy(r->r)*4); + r = r2; + } + premulalpha(r); + if(scale.x > 1 || scale.y > 1){ upscaledraw(r, dst, off, scale, ctl->upfilter); qunlock(ctl); - if(r2 != nil) freeraster(r2); + freeraster(r2); return; } @@ -259,17 +291,30 @@ framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scal // } // procpoolwait(turbodrawingpool); // free(tasks); - loadimage(dst, rectaddpt(sr, dst->r.min), (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4); + + tmp = allocimage(display, sr, RGBA32, 0, DNofill); + if(tmp == nil) + sysfatal("allocimage: %r"); + + loadimage(tmp, sr, (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4); + draw(dst, rectaddpt(sr, dst->r.min), tmp, nil, ZP); + freeimage(tmp); }else if(rectclip(&sr, dr)){ + tmp = allocimage(display, sr, RGBA32, 0, DNofill); + if(tmp == nil) + sysfatal("allocimage: %r"); + dr = sr; dr.max.y = dr.min.y + 1; /* remove offset to get the actual rect within the framebuffer */ sr = rectsubpt(sr, off); for(; sr.min.y < sr.max.y; sr.min.y++, dr.min.y++, dr.max.y++) - loadimage(dst, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4); + loadimage(tmp, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4); + draw(dst, rectaddpt(tmp->r, dst->r.min), tmp, nil, tmp->r.min); + freeimage(tmp); } qunlock(ctl); - if(r2 != nil) freeraster(r2); + freeraster(r2); } static void @@ -278,11 +323,15 @@ upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter) void (*filterfn)(ulong*, Raster*, Point); Rectangle blkr; Point sp, dp; + Memimage *tmp; ulong *blk; filterfn = nil; blk = emalloc(scale.x*scale.y*4); blkr = Rect(0,0,scale.x,scale.y); + tmp = allocmemimage(dst->r, RGBA32); + if(tmp == nil) + sysfatal("allocmemimage: %r"); switch(filter){ case UFScale2x: @@ -301,8 +350,10 @@ upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter) filterfn(blk, fb, sp); else memsetl(blk, getpixel(fb, sp), scale.x*scale.y); - loadmemimage(dst, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4); + loadmemimage(tmp, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4); } + memimagedraw(dst, dst->r, tmp, tmp->r.min, nil, ZP, S); + freememimage(tmp); free(blk); } @@ -312,6 +363,7 @@ framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, char *name, Point off, Poin Framebuf *fb; Raster *r, *r2; Rectangle sr, dr; + Memimage *tmp; qlock(ctl); fb = ctl->getfb(ctl); @@ -329,27 +381,47 @@ framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, char *name, Point off, Poin r = r2; } + /* this means the raster is a color one, so duplicate it */ + if(r2 == nil){ + r2 = allocraster(nil, r->r, COLOR32); + memmove(r2->data, r->data, Dx(r->r)*Dy(r->r)*4); + r = r2; + } + premulalpha(r); + if(scale.x > 1 || scale.y > 1){ upscalememdraw(r, dst, off, scale, ctl->upfilter); qunlock(ctl); - if(r2 != nil) freeraster(r2); + freeraster(r2); return; } sr = rectaddpt(fb->r, off); dr = rectsubpt(dst->r, dst->r.min); - if(rectinrect(sr, dr)) - loadmemimage(dst, rectaddpt(sr, dst->r.min), (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4); - else if(rectclip(&sr, dr)){ + if(rectinrect(sr, dr)){ + tmp = allocmemimage(sr, RGBA32); + if(tmp == nil) + sysfatal("allocmemimage: %r"); + + loadmemimage(tmp, sr, (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4); + memimagedraw(dst, rectaddpt(sr, dst->r.min), tmp, ZP, nil, ZP, S); + freememimage(tmp); + }else if(rectclip(&sr, dr)){ + tmp = allocmemimage(sr, RGBA32); + if(tmp == nil) + sysfatal("allocmemimage: %r"); + dr = sr; dr.max.y = dr.min.y + 1; /* remove offset to get the actual rect within the framebuffer */ sr = rectsubpt(sr, off); for(; sr.min.y < sr.max.y; sr.min.y++, dr.min.y++, dr.max.y++) - loadmemimage(dst, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4); + loadmemimage(tmp, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4); + memimagedraw(dst, rectaddpt(tmp->r, dst->r.min), tmp, tmp->r.min, nil, ZP, S); + freememimage(tmp); } qunlock(ctl); - if(r2 != nil) freeraster(r2); + freeraster(r2); } static void @@ -371,7 +443,7 @@ resetAbuf(Abuf *buf) } static void -framebufctl_reset(Framebufctl *ctl, ulong clr) +framebufctl_reset(Framebufctl *ctl) { Framebuf *fb; Raster *r; @@ -381,7 +453,7 @@ framebufctl_reset(Framebufctl *ctl, ulong clr) resetAbuf(&fb->abuf); r = fb->rasters; /* color buffer */ - clearraster(r, rgba2xrgb(clr)); + clearraster(r, 0); r = r->next; /* z-buffer */ fclearraster(r, Inf(-1)); while((r = r->next) != nil) @@ -515,6 +587,8 @@ rastergetfloat(Raster *r, Point p) void freeraster(Raster *r) { + if(r == nil) + return; free(r->data); free(r->name); free(r); |