summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2024-08-17 12:17:46 +0000
committerrodri <rgl@antares-labs.eu>2024-08-17 12:17:46 +0000
commit56e8e3de24e7fea36f165b653a8efc8c38145d4c (patch)
treec1558a4ef810d82a11d31ab085dd849c7b5bba7f
parentd0a7561dd20847504b2449e17fd791f6c2800c84 (diff)
downloadlibgraphics-56e8e3de24e7fea36f165b653a8efc8c38145d4c.tar.gz
libgraphics-56e8e3de24e7fea36f165b653a8efc8c38145d4c.tar.bz2
libgraphics-56e8e3de24e7fea36f165b653a8efc8c38145d4c.zip
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.
-rw-r--r--camera.c4
-rw-r--r--fb.c70
-rw-r--r--graphics.h6
-rw-r--r--viewport.c23
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;
@@ -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;
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);