diff options
-rw-r--r-- | camera.c | 2 | ||||
-rw-r--r-- | color.c | 40 | ||||
-rw-r--r-- | fb.c | 102 | ||||
-rw-r--r-- | graphics.h | 15 | ||||
-rw-r--r-- | render.c | 26 | ||||
-rw-r--r-- | texture.c | 7 | ||||
-rw-r--r-- | util.c | 42 |
7 files changed, 181 insertions, 53 deletions
@@ -241,7 +241,7 @@ shootcamera(Camera *c, Shadertab *s) job->shaders = s; job->donec = chancreate(sizeof(void*), 0); - fbctl->reset(fbctl, c->clearcolor); + fbctl->reset(fbctl); t0 = nanosec(); sendp(c->rctl->jobq, job); recvp(job->donec); @@ -8,6 +8,39 @@ #include "graphics.h" #include "internal.h" +ulong +col2ul(Color c) +{ + uchar cbuf[4]; + + cbuf[0] = fclamp(c.a, 0, 1)*0xFF; + cbuf[1] = fclamp(c.b, 0, 1)*0xFF; + cbuf[2] = fclamp(c.g, 0, 1)*0xFF; + cbuf[3] = fclamp(c.r, 0, 1)*0xFF; + return cbuf[3]<<24 | cbuf[2]<<16 | cbuf[1]<<8 | cbuf[0]; +} + +Color +ul2col(ulong l) +{ + Color c; + + c.a = (l & 0xff)/255.0; + c.b = (l>>8 & 0xff)/255.0; + c.g = (l>>16 & 0xff)/255.0; + c.r = (l>>24 & 0xff)/255.0; + return c; +} + +int +hasalpha(ulong chan) +{ + for(; chan; chan >>= 8) + if(TYPE(chan) == CAlpha) + return 1; + return 0; +} + /* * see also “The Importance of Being Linear”, Gritz and d'Eon, GPU Gems 3, Ch. 24, December 2007 */ @@ -141,13 +174,6 @@ linear2srgb(Color c) return c; } -ulong -rgba2xrgb(ulong c) -{ - return (c & 0xFF)<<24|(c>>24 & 0xFF)<<16| - (c>>16 & 0xFF)<<8|(c>>8 & 0xFF); -} - /* tone mapping */ @@ -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); @@ -24,8 +24,8 @@ enum { LightSpot, /* raster formats */ - COLOR32 = 0, - FLOAT32, + COLOR32 = 0, /* RGBA32 */ + FLOAT32, /* F32 */ /* texture formats */ RAWTexture = 0, /* unmanaged */ @@ -314,7 +314,7 @@ struct Framebufctl void (*draw)(Framebufctl*, Image*, char*, Point, Point); void (*memdraw)(Framebufctl*, Memimage*, char*, Point, Point); void (*swap)(Framebufctl*); - void (*reset)(Framebufctl*, ulong); + void (*reset)(Framebufctl*); void (*createraster)(Framebufctl*, char*, ulong); Raster *(*fetchraster)(Framebufctl*, char*); Framebuf *(*getfb)(Framebufctl*); @@ -350,7 +350,6 @@ struct Camera } clip; Matrix3 proj; /* VCS to clip space xform */ Projection projtype; - ulong clearcolor; int cullmode; int enableblend; int enabledepth; @@ -431,14 +430,20 @@ Color samplecubemap(Cubemap*, Point3, Color(*)(Texture*, Point2)); /* util */ Point2 modulapt2(Point2, Point2); +Point2 minpt2(Point2, Point2); +Point2 maxpt2(Point2, Point2); Point3 modulapt3(Point3, Point3); +Point3 minpt3(Point3, Point3); +Point3 maxpt3(Point3, Point3); Memimage *rgb(ulong); Memimage *dupmemimage(Memimage*); /* color */ +ulong col2ul(Color); +Color ul2col(ulong); +int hasalpha(ulong); Color srgb2linear(Color); Color linear2srgb(Color); -ulong rgba2xrgb(ulong); Color aces(Color); Color aces2(Color); @@ -11,8 +11,6 @@ Rectangle UR = {0,0,1,1}; //Procpool *turbodrawingpool; -static ulong col2ul(Color); - static Vertexattr * sparams_getuniform(Shaderparams *sp, char *id) { @@ -59,30 +57,6 @@ sparams_toraster(Shaderparams *sp, char *rname, void *v) } } -static ulong -col2ul(Color c) -{ - uchar cbuf[4]; - - cbuf[0] = fclamp(c.b, 0, 1)*0xFF; - cbuf[1] = fclamp(c.g, 0, 1)*0xFF; - cbuf[2] = fclamp(c.r, 0, 1)*0xFF; - cbuf[3] = fclamp(c.a, 0, 1)*0xFF; - return cbuf[3]<<24 | cbuf[2]<<16 | cbuf[1]<<8 | cbuf[0]; -} - -static Color -ul2col(ulong l) -{ - Color c; - - c.b = (l & 0xff)/255.0; - c.g = (l>>8 & 0xff)/255.0; - c.r = (l>>16 & 0xff)/255.0; - c.a = (l>>24 & 0xff)/255.0; - return c; -} - static void pixel(Raster *fb, Point p, Color c, int blend) { @@ -48,6 +48,7 @@ _memreadcolor(Texture *t, Point sp) uchar cbuf[4]; switch(t->image->chan){ + default: sysfatal("unsupported texture format"); case RGB24: unloadmemimage(t->image, rectaddpt(UR, sp), cbuf+1, sizeof cbuf - 1); cbuf[0] = 0xFF; @@ -63,6 +64,12 @@ _memreadcolor(Texture *t, Point sp) } c = cbuf2col(cbuf); + /* remove pre-multiplied alpha */ + if(hasalpha(t->image->chan) && c.a > 0 && c.a < 1){ + c.r /= c.a; + c.g /= c.a; + c.b /= c.a; + } switch(t->type){ case sRGBTexture: c = srgb2linear(c); break; } @@ -14,12 +14,54 @@ modulapt2(Point2 a, Point2 b) return (Point2){a.x*b.x, a.y*b.y, a.w*b.w}; } +Point2 +minpt2(Point2 a, Point2 b) +{ + return (Point2){ + min(a.x, b.x), + min(a.y, b.y), + min(a.w, b.w) + }; +} + +Point2 +maxpt2(Point2 a, Point2 b) +{ + return (Point2){ + max(a.x, b.x), + max(a.y, b.y), + max(a.w, b.w) + }; +} + Point3 modulapt3(Point3 a, Point3 b) { return (Point3){a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; } +Point3 +minpt3(Point3 a, Point3 b) +{ + return (Point3){ + min(a.x, b.x), + min(a.y, b.y), + min(a.z, b.z), + min(a.w, b.w) + }; +} + +Point3 +maxpt3(Point3 a, Point3 b) +{ + return (Point3){ + max(a.x, b.x), + max(a.y, b.y), + max(a.z, b.z), + max(a.w, b.w) + }; +} + void memsetf(void *dp, float v, usize len) { |