diff options
-rw-r--r-- | camera.c | 4 | ||||
-rw-r--r-- | fb.c | 70 | ||||
-rw-r--r-- | graphics.h | 6 | ||||
-rw-r--r-- | viewport.c | 23 |
4 files changed, 70 insertions, 33 deletions
@@ -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; @@ -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; @@ -193,6 +201,36 @@ framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point off, Point sca } 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) { Framebuf *fb; @@ -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; @@ -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); @@ -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); |