From c47e5c9807a0d3bf86c2bc227482584aaca7bb9c Mon Sep 17 00:00:00 2001 From: rodri Date: Fri, 2 Aug 2024 15:22:46 +0000 Subject: add a viewport upscale filters interface. --- fb.c | 115 ++++++++++++++++++++++++++++++++++++++++++------------------- graphics.h | 9 +++++ viewport.c | 29 +++++++++++----- 3 files changed, 109 insertions(+), 44 deletions(-) diff --git a/fb.c b/fb.c index e71312a..2cf05da 100644 --- a/fb.c +++ b/fb.c @@ -14,15 +14,15 @@ * see https://www.scale2x.it/algorithm */ static void -scale2x_filter(ulong *dst, Framebuf *fb, Point *sp) +scale2x_filter(ulong *dst, Framebuf *fb, Point sp) { ulong B, D, E, F, H; - E = getpixel(fb, *sp); - B = sp->y == fb->r.min.y? E: getpixel(fb, addpt(*sp, Pt( 0,-1))); - D = sp->x == fb->r.min.x? E: getpixel(fb, addpt(*sp, Pt(-1, 0))); - F = sp->x == fb->r.max.x? E: getpixel(fb, addpt(*sp, Pt( 1, 0))); - H = sp->y == fb->r.max.y? E: getpixel(fb, addpt(*sp, Pt( 0, 1))); + E = getpixel(fb, sp); + B = sp.y == fb->r.min.y? E: getpixel(fb, addpt(sp, Pt( 0,-1))); + D = sp.x == fb->r.min.x? E: getpixel(fb, addpt(sp, Pt(-1, 0))); + F = sp.x == fb->r.max.x? E: getpixel(fb, addpt(sp, Pt( 1, 0))); + H = sp.y == fb->r.max.y? E: getpixel(fb, addpt(sp, Pt( 0, 1))); if(B != H && D != F){ dst[0] = D == B? D: E; @@ -34,27 +34,27 @@ scale2x_filter(ulong *dst, Framebuf *fb, Point *sp) } static void -scale3x_filter(ulong *dst, Framebuf *fb, Point *sp) +scale3x_filter(ulong *dst, Framebuf *fb, Point sp) { ulong A, B, C, D, E, F, G, H, I; - E = getpixel(fb, *sp); - B = sp->y == fb->r.min.y? E: getpixel(fb, addpt(*sp, Pt( 0,-1))); - D = sp->x == fb->r.min.x? E: getpixel(fb, addpt(*sp, Pt(-1, 0))); - F = sp->x == fb->r.max.x? E: getpixel(fb, addpt(*sp, Pt( 1, 0))); - H = sp->y == fb->r.max.y? E: getpixel(fb, addpt(*sp, Pt( 0, 1))); - A = sp->y == fb->r.min.y && sp->x == fb->r.min.x? E: - sp->y == fb->r.min.y? D: sp->x == fb->r.min.x? B: - getpixel(fb, addpt(*sp, Pt(-1,-1))); - C = sp->y == fb->r.min.y && sp->x == fb->r.max.x? E: - sp->y == fb->r.min.y? F: sp->x == fb->r.max.x? B: - getpixel(fb, addpt(*sp, Pt( 1,-1))); - G = sp->y == fb->r.max.y && sp->x == fb->r.min.x? E: - sp->y == fb->r.max.y? D: sp->x == fb->r.min.x? H: - getpixel(fb, addpt(*sp, Pt(-1, 1))); - I = sp->y == fb->r.max.y && sp->x == fb->r.max.x? E: - sp->y == fb->r.max.y? F: sp->x == fb->r.max.x? H: - getpixel(fb, addpt(*sp, Pt( 1, 1))); + E = getpixel(fb, sp); + B = sp.y == fb->r.min.y? E: getpixel(fb, addpt(sp, Pt( 0,-1))); + D = sp.x == fb->r.min.x? E: getpixel(fb, addpt(sp, Pt(-1, 0))); + F = sp.x == fb->r.max.x? E: getpixel(fb, addpt(sp, Pt( 1, 0))); + H = sp.y == fb->r.max.y? E: getpixel(fb, addpt(sp, Pt( 0, 1))); + A = sp.y == fb->r.min.y && sp.x == fb->r.min.x? E: + sp.y == fb->r.min.y? D: sp.x == fb->r.min.x? B: + getpixel(fb, addpt(sp, Pt(-1,-1))); + C = sp.y == fb->r.min.y && sp.x == fb->r.max.x? E: + sp.y == fb->r.min.y? F: sp.x == fb->r.max.x? B: + getpixel(fb, addpt(sp, Pt( 1,-1))); + G = sp.y == fb->r.max.y && sp.x == fb->r.min.x? E: + sp.y == fb->r.max.y? D: sp.x == fb->r.min.x? H: + getpixel(fb, addpt(sp, Pt(-1, 1))); + I = sp.y == fb->r.max.y && sp.x == fb->r.max.x? E: + sp.y == fb->r.max.y? F: sp.x == fb->r.max.x? H: + getpixel(fb, addpt(sp, Pt( 1, 1))); if(B != H && D != F){ dst[0] = D == B? D: E; @@ -71,11 +71,27 @@ scale3x_filter(ulong *dst, Framebuf *fb, Point *sp) } //static void -//scale4x_filter(ulong *dst, Framebuf *fb, Point *sp) +//scale4x_filter(ulong *dst, Framebuf *fb, Point sp) //{ // //} +//static void +//framebufctl_draw⁻¹(Framebufctl *ctl, Image *dst) +//{ +// Framebuf *fb; +// Rectangle lr; +// Point sp, dp; +// +// qlock(ctl); +// fb = ctl->getfb(ctl); +// lr = Rect(0,0,Dx(fb->r),1); +// sp.x = dp.x = 0; +// for(sp.y = fb->r.max.y, dp.y = dst->r.min.y; sp.y >= fb->r.min.y; sp.y--, dp.y++) +// loadimage(dst, rectaddpt(lr, dp), (uchar*)(fb->cb + sp.y*Dx(lr)), Dx(lr)*4); +// qunlock(ctl); +//} + static void framebufctl_draw(Framebufctl *ctl, Image *dst) { @@ -83,30 +99,43 @@ framebufctl_draw(Framebufctl *ctl, Image *dst) qlock(ctl); fb = ctl->getfb(ctl); - loadimage(dst, rectaddpt(fb->r, dst->r.min), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4); + loadimage(dst, dst->r, (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4); qunlock(ctl); } static void framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point scale) { + void (*filter)(ulong*, Framebuf*, Point); Framebuf *fb; Rectangle blkr; Point sp, dp; ulong *blk; + filter = nil; blk = emalloc(scale.x*scale.y*4); blkr = Rect(0,0,scale.x,scale.y); qlock(ctl); fb = ctl->getfb(ctl); + + switch(ctl->upfilter){ + case UFScale2x: + if(scale.x == scale.y && scale.y == 2) + filter = scale2x_filter; + break; + case UFScale3x: + if(scale.x == scale.y && scale.y == 3) + filter = scale3x_filter; + break; + } + for(sp.y = fb->r.min.y, dp.y = dst->r.min.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y) for(sp.x = fb->r.min.x, dp.x = dst->r.min.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){ - /*if(scale.x == 2 && scale.y == 2) - scale2x_filter(blk, fb, &sp); - else if(scale.x == 3 && scale.y == 3) - scale3x_filter(blk, fb, &sp); - else */memsetl(blk, getpixel(fb, sp), scale.x*scale.y); + if(filter != nil) + filter(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); } qunlock(ctl); @@ -127,23 +156,36 @@ framebufctl_memdraw(Framebufctl *ctl, Memimage *dst) static void framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point scale) { + void (*filter)(ulong*, Framebuf*, Point); Framebuf *fb; Rectangle blkr; Point sp, dp; ulong *blk; + filter = nil; blk = emalloc(scale.x*scale.y*4); blkr = Rect(0,0,scale.x,scale.y); qlock(ctl); fb = ctl->getfb(ctl); + + switch(ctl->upfilter){ + case UFScale2x: + if(scale.x == scale.y && scale.y == 2) + filter = scale2x_filter; + break; + case UFScale3x: + if(scale.x == scale.y && scale.y == 3) + filter = scale3x_filter; + break; + } + for(sp.y = fb->r.min.y, dp.y = dst->r.min.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y) for(sp.x = fb->r.min.x, dp.x = dst->r.min.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){ - /*if(scale.x == 2 && scale.y == 2) - scale2x_filter(blk, fb, &sp); - else if(scale.x == 3 && scale.y == 3) - scale3x_filter(blk, fb, &sp); - else */memsetl(blk, getpixel(fb, sp), scale.x*scale.y); + if(filter != nil) + filter(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); } qunlock(ctl); @@ -211,6 +253,7 @@ mkfb(Rectangle r) void rmfb(Framebuf *fb) { + free(fb->nb); free(fb->zb); free(fb->cb); free(fb); diff --git a/graphics.h b/graphics.h index 476f954..52becf3 100644 --- a/graphics.h +++ b/graphics.h @@ -25,6 +25,12 @@ enum { RAWTexture = 0, /* unmanaged */ sRGBTexture, + /* upscaling filters */ + UFNone = 0, /* nearest neighbour */ + UFScale2x, + UFScale3x, + UFScale4x, + /* vertex attribute types */ VAPoint = 0, VANumber, @@ -253,6 +259,7 @@ struct Framebufctl QLock; Framebuf *fb[2]; /* double buffering */ uint idx; /* front buffer index */ + uint upfilter; /* upscaling filter */ void (*draw)(Framebufctl*, Image*); void (*upscaledraw)(Framebufctl*, Image*, Point); @@ -273,6 +280,8 @@ struct Viewport void (*draw)(Viewport*, Image*); void (*memdraw)(Viewport*, Memimage*); + void (*setscale)(Viewport*, double, double); + void (*setscalefilter)(Viewport*, int); Framebuf *(*getfb)(Viewport*); }; diff --git a/viewport.c b/viewport.c index d37a12c..b3be122 100644 --- a/viewport.c +++ b/viewport.c @@ -13,11 +13,9 @@ viewport_draw(Viewport *v, Image *dst) { Point scale; - scale.x = Dx(dst->r)/Dx(v->r); - scale.y = Dy(dst->r)/Dy(v->r); - /* no downsampling support yet */ - assert(scale.x > 0 && scale.y > 0); + scale.x = max(min(v->bx.x, Dx(dst->r)/Dx(v->r)), 1); + scale.y = max(min(v->by.y, Dy(dst->r)/Dy(v->r)), 1); if(scale.x > 1 || scale.y > 1) v->fbctl->upscaledraw(v->fbctl, dst, scale); @@ -30,11 +28,9 @@ viewport_memdraw(Viewport *v, Memimage *dst) { Point scale; - scale.x = Dx(dst->r)/Dx(v->r); - scale.y = Dy(dst->r)/Dy(v->r); - /* no downsampling support yet */ - assert(scale.x > 0 && scale.y > 0); + scale.x = max(min(v->bx.x, Dx(dst->r)/Dx(v->r)), 1); + scale.y = max(min(v->by.y, Dy(dst->r)/Dy(v->r)), 1); if(scale.x > 1 || scale.y > 1) v->fbctl->upscalememdraw(v->fbctl, dst, scale); @@ -42,6 +38,21 @@ viewport_memdraw(Viewport *v, Memimage *dst) v->fbctl->memdraw(v->fbctl, dst); } +static void +viewport_setscale(Viewport *v, double sx, double sy) +{ + assert(sx > 0 && sy > 0); + + v->bx.x = sx; + v->by.y = sy; +} + +static void +viewport_setscalefilter(Viewport *v, int f) +{ + v->fbctl->upfilter = f; +} + static Framebuf * viewport_getfb(Viewport *v) { @@ -61,6 +72,8 @@ mkviewport(Rectangle r) v->r = r; v->draw = viewport_draw; v->memdraw = viewport_memdraw; + v->setscale = viewport_setscale; + v->setscalefilter = viewport_setscalefilter; v->getfb = viewport_getfb; return v; } -- cgit v1.2.3