From 56e8e3de24e7fea36f165b653a8efc8c38145d4c Mon Sep 17 00:00:00 2001 From: rodri Date: Sat, 17 Aug 2024 12:17:46 +0000 Subject: unify drawing routines and add clipped fb drawing support. now changing the viewport offset will correctly show the portion of the framebuffer that's visible, including support for upscaled views. --- camera.c | 4 ++++ fb.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++--------------- graphics.h | 6 ++---- viewport.c | 23 ++++++++++----------- 4 files changed, 70 insertions(+), 33 deletions(-) diff --git a/camera.c b/camera.c index e67601f..ccd1f57 100644 --- a/camera.c +++ b/camera.c @@ -114,6 +114,10 @@ Cam(Rectangle vr, Renderer *r, Projection p, double fov, double n, double f) c = newcamera(); c->view = mkviewport(vr); + if(c->view == nil){ + werrstr("mkviewport: %r"); + return nil; + } c->rctl = r; configcamera(c, p, fov, n, f); return c; diff --git a/fb.c b/fb.c index 4b1f82e..2c1d494 100644 --- a/fb.c +++ b/fb.c @@ -93,18 +93,7 @@ scale3x_filter(ulong *dst, Framebuf *fb, Point sp) //} static void -framebufctl_draw(Framebufctl *ctl, Image *dst, Point off) -{ - Framebuf *fb; - - qlock(ctl); - fb = ctl->getfb(ctl); - loadimage(dst, rectaddpt(fb->r, addpt(dst->r.min, off)), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4); - qunlock(ctl); -} - -static void -framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point off, Point scale) +upscaledraw(Framebufctl *ctl, Image *dst, Point off, Point scale) { void (*filter)(ulong*, Framebuf*, Point); Framebuf *fb; @@ -143,18 +132,37 @@ framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point off, Point scale) } static void -framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, Point off) +framebufctl_draw(Framebufctl *ctl, Image *dst, Point off, Point scale) { Framebuf *fb; + Rectangle sr, dr; + ulong *cb; + int y; + + if(scale.x > 1 || scale.y > 1){ + upscaledraw(ctl, dst, off, scale); + return; + } qlock(ctl); fb = ctl->getfb(ctl); - loadmemimage(dst, rectaddpt(fb->r, addpt(dst->r.min, off)), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4); + sr = rectaddpt(fb->r, off); + dr = rectsubpt(dst->r, dst->r.min); + if(rectinrect(sr, dr)) + loadimage(dst, rectaddpt(sr, dst->r.min), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4); + else if(rectclip(&sr, dr)){ + cb = emalloc(Dx(sr)*Dy(sr)*4); + /* TODO there must be a cleaner way to do this */ + for(y = sr.min.y; y < sr.max.y; y++) + memmove(&cb[(y - sr.min.y)*Dx(sr)], &fb->cb[max(y - off.y,0)*Dx(fb->r) + max(-off.x,0)], Dx(sr)*4); + loadimage(dst, rectaddpt(sr, dst->r.min), (uchar*)cb, Dx(sr)*Dy(sr)*4); + free(cb); + } qunlock(ctl); } static void -framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point off, Point scale) +upscalememdraw(Framebufctl *ctl, Memimage *dst, Point off, Point scale) { void (*filter)(ulong*, Framebuf*, Point); Framebuf *fb; @@ -192,6 +200,36 @@ framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point off, Point sca free(blk); } +static void +framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, Point off, Point scale) +{ + Framebuf *fb; + Rectangle sr, dr; + ulong *cb; + int y; + + if(scale.x > 1 || scale.y > 1){ + upscalememdraw(ctl, dst, off, scale); + return; + } + + qlock(ctl); + fb = ctl->getfb(ctl); + sr = rectaddpt(fb->r, off); + dr = rectsubpt(dst->r, dst->r.min); + if(rectinrect(sr, dr)) + loadmemimage(dst, rectaddpt(sr, dst->r.min), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4); + else if(rectclip(&sr, dr)){ + cb = emalloc(Dx(sr)*Dy(sr)*4); + /* TODO there must be a cleaner way to do this */ + for(y = sr.min.y; y < sr.max.y; y++) + memmove(&cb[(y - sr.min.y)*Dx(sr)], &fb->cb[max(y - off.y,0)*Dx(fb->r) + max(-off.x,0)], Dx(sr)*4); + loadmemimage(dst, rectaddpt(sr, dst->r.min), (uchar*)cb, Dx(sr)*Dy(sr)*4); + free(cb); + } + qunlock(ctl); +} + static void framebufctl_drawnormals(Framebufctl *ctl, Image *dst) { @@ -280,9 +318,7 @@ mkfbctl(Rectangle r) fc->fb[0] = mkfb(r); fc->fb[1] = mkfb(r); fc->draw = framebufctl_draw; - fc->upscaledraw = framebufctl_upscaledraw; fc->memdraw = framebufctl_memdraw; - fc->upscalememdraw = framebufctl_upscalememdraw; fc->drawnormals = framebufctl_drawnormals; fc->swap = framebufctl_swap; fc->reset = framebufctl_reset; diff --git a/graphics.h b/graphics.h index 6362075..1360210 100644 --- a/graphics.h +++ b/graphics.h @@ -287,10 +287,8 @@ struct Framebufctl uint idx; /* front buffer index */ uint upfilter; /* upscaling filter */ - void (*draw)(Framebufctl*, Image*, Point); - void (*upscaledraw)(Framebufctl*, Image*, Point, Point); - void (*memdraw)(Framebufctl*, Memimage*, Point); - void (*upscalememdraw)(Framebufctl*, Memimage*, Point, Point); + void (*draw)(Framebufctl*, Image*, Point, Point); + void (*memdraw)(Framebufctl*, Memimage*, Point, Point); void (*drawnormals)(Framebufctl*, Image*); void (*swap)(Framebufctl*); void (*reset)(Framebufctl*, ulong); diff --git a/viewport.c b/viewport.c index 9e41e53..5214e53 100644 --- a/viewport.c +++ b/viewport.c @@ -15,13 +15,10 @@ viewport_draw(Viewport *v, Image *dst) off = Pt(v->p.x, v->p.y); /* no downsampling support yet */ - 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); + scale.x = max(v->bx.x, 1); + scale.y = max(v->by.y, 1); - if(scale.x > 1 || scale.y > 1) - v->fbctl->upscaledraw(v->fbctl, dst, off, scale); - else - v->fbctl->draw(v->fbctl, dst, off); + v->fbctl->draw(v->fbctl, dst, off, scale); } static void @@ -31,13 +28,10 @@ viewport_memdraw(Viewport *v, Memimage *dst) off = Pt(v->p.x, v->p.y); /* no downsampling support yet */ - 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); + scale.x = max(v->bx.x, 1); + scale.y = max(v->by.y, 1); - if(scale.x > 1 || scale.y > 1) - v->fbctl->upscalememdraw(v->fbctl, dst, off, scale); - else - v->fbctl->memdraw(v->fbctl, dst, off); + v->fbctl->memdraw(v->fbctl, dst, off, scale); } static void @@ -78,6 +72,11 @@ mkviewport(Rectangle r) { Viewport *v; + if(badrect(r)){ + werrstr("bad viewport rectangle"); + return nil; + } + v = emalloc(sizeof *v); v->p = Pt2(0,0,1); v->bx = Vec2(1,0); -- cgit v1.2.3