diff options
author | rodri <rgl@antares-labs.eu> | 2024-08-10 17:57:02 +0000 |
---|---|---|
committer | rodri <rgl@antares-labs.eu> | 2024-08-10 17:57:02 +0000 |
commit | d3b48593b0fee862ea60687336031fd9374ab667 (patch) | |
tree | 7810bcb85cbba3beee05e89b911c35f1d8e1b769 | |
parent | 6eab9793d68feb3282714083b355d38c6c36400b (diff) | |
download | libgraphics-d3b48593b0fee862ea60687336031fd9374ab667.tar.gz libgraphics-d3b48593b0fee862ea60687336031fd9374ab667.tar.bz2 libgraphics-d3b48593b0fee862ea60687336031fd9374ab667.zip |
experimental A-buffer implementation.
very simple, without anti-aliasing, made for getting
OIT (order independent transparency) rendering of
arbitrary objects.
also added switches for blending, depth testing and the
A-buffer to the camera.
-rw-r--r-- | camera.c | 1 | ||||
-rw-r--r-- | fb.c | 11 | ||||
-rw-r--r-- | graphics.h | 29 | ||||
-rw-r--r-- | render.c | 106 |
4 files changed, 132 insertions, 15 deletions
@@ -126,6 +126,7 @@ newcamera(void) c = emalloc(sizeof *c); memset(c, 0, sizeof *c); + c->enabledepth = 1; return c; } @@ -212,12 +212,23 @@ framebufctl_swap(Framebufctl *ctl) } static void +resetAbuf(Abuf *buf) +{ + while(buf->nact--) + free(buf->act[buf->nact]->items); + free(buf->act); + free(buf->stk); + memset(buf, 0, sizeof *buf); +} + +static void framebufctl_reset(Framebufctl *ctl) { Framebuf *fb; /* address the back buffer—resetting the front buffer is VERBOTEN */ fb = ctl->getbb(ctl); + resetAbuf(&fb->abuf); memset(fb->nb, 0, Dx(fb->r)*Dy(fb->r)*4); memsetf(fb->zb, Inf(-1), Dx(fb->r)*Dy(fb->r)); memset(fb->cb, 0, Dx(fb->r)*Dy(fb->r)*4); @@ -54,6 +54,9 @@ typedef struct Shadertab Shadertab; typedef struct Renderer Renderer; typedef struct Rendertime Rendertime; typedef struct Renderjob Renderjob; +typedef struct Fragment Fragment; +typedef struct Astk Astk; +typedef struct Abuf Abuf; typedef struct Framebuf Framebuf; typedef struct Framebufctl Framebufctl; typedef struct Viewport Viewport; @@ -246,11 +249,34 @@ struct Renderjob Renderjob *next; }; +struct Fragment +{ + Color c; + float z; +}; + +struct Astk +{ + Point p; + Fragment *items; + ulong size; + int active; +}; + +struct Abuf +{ + QLock; + Astk *stk; /* framebuffer fragment stacks */ + Astk **act; /* active fragment stacks */ + ulong nact; +}; + struct Framebuf { ulong *cb; /* color buffer */ float *zb; /* z/depth buffer */ ulong *nb; /* normals buffer (DBG only) */ + Abuf abuf; /* A-buffer */ Rectangle r; }; @@ -300,6 +326,9 @@ struct Camera Matrix3 proj; /* VCS to clip space xform */ Projection projtype; int cullmode; + int enableblend; + int enabledepth; + int enableAbuff; struct { uvlong min, avg, max, acc, n, v; @@ -35,12 +35,14 @@ ul2col(ulong l) } static void -pixel(Framebuf *fb, Point p, Color c) +pixel(Framebuf *fb, Point p, Color c, int blend) { Color dc; - dc = srgb2linear(ul2col(getpixel(fb, p))); - c = lerp3(dc, c, c.a); /* SoverD */ + if(blend){ + dc = srgb2linear(ul2col(getpixel(fb, p))); + c = lerp3(dc, c, c.a); /* SoverD */ + } putpixel(fb, p, col2ul(linear2srgb(c))); } @@ -75,6 +77,57 @@ isfacingback(Primitive *p) return sa <= 0; } +static void +pushtoAbuf(Framebuf *fb, Point p, Color c, float z) +{ + Abuf *buf; + Astk *stk; + int i; + + buf = &fb->abuf; + stk = &buf->stk[p.y*Dx(fb->r) + p.x]; + stk->items = erealloc(stk->items, ++stk->size*sizeof(*stk->items)); + +//fprint(2, "stk %#p items %#p size %lud (%d bytes)\n", stk, stk->items, stk->size, sizeof(*stk)); + + for(i = 0; i < stk->size; i++) + if(z < stk->items[i].z) + break; + + if(i < stk->size){ + memmove(&stk->items[i+1], &stk->items[i], (stk->size-1 - i)*sizeof(*stk->items)); + stk->items[i] = (Fragment){c, z}; + }else + stk->items[stk->size-1] = (Fragment){c, z}; + + if(!stk->active){ + stk->active++; + stk->p = p; + qlock(buf); + buf->act = erealloc(buf->act, ++buf->nact*sizeof(*buf->act)); + buf->act[buf->nact-1] = stk; + qunlock(buf); +//fprint(2, "act %#p nact %lud (%d bytes)\n", buf->act, buf->nact, sizeof(*buf->act)); + } +} + +static void +squashAbuf(Framebuf *fb, int blend) +{ + Abuf *buf; + Astk *stk; + int i; + + buf = &fb->abuf; + for(i = 0; i < buf->nact; i++){ + stk = buf->act[i]; + while(stk->size--) + pixel(fb, stk->p, stk->items[stk->size].c, blend); + /* write to the depth buffer as well */ +// fb->zb[stk->p.x + stk->p.y*Dx(fb->r)] = stk->items[stk->size].z; + } +} + static Point3 _barycoords(Triangle2 t, Point2 p) { @@ -115,14 +168,19 @@ rasterize(Rastertask *task) p = Pt(prim.v[0].p.x, prim.v[0].p.y); z = fclamp(prim.v[0].p.z, 0, 1); - if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) - break; - params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + if(params->camera->enabledepth){ + if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + break; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + } fsp.v = dupvertex(&prim.v[0]); fsp.p = p; c = params->fshader(&fsp); - pixel(params->fb, p, c); + if(params->camera->enableAbuff) + pushtoAbuf(params->fb, p, c, z); + else + pixel(params->fb, p, c, params->camera->enableblend); delvattrs(&fsp.v); break; case PLine: @@ -159,9 +217,11 @@ rasterize(Rastertask *task) z = flerp(prim.v[0].p.z, prim.v[1].p.z, perc); /* TODO get rid of the bounds check and make sure the clipping doesn't overflow */ - if(!ptinrect(p, params->fb->r) || z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) - goto discard; - params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + if(params->camera->enabledepth){ + if(!ptinrect(p, params->fb->r) || z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + goto discard; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + } /* interpolate z⁻¹ and get actual z */ z = flerp(prim.v[0].p.w, prim.v[1].p.w, perc); @@ -173,7 +233,10 @@ rasterize(Rastertask *task) fsp.p = p; c = params->fshader(&fsp); - pixel(params->fb, p, c); + if(params->camera->enableAbuff) + pushtoAbuf(params->fb, p, c, z); + else + pixel(params->fb, p, c, params->camera->enableblend); delvattrs(&fsp.v); discard: if(steep) SWAP(int, &p.x, &p.y); @@ -206,9 +269,11 @@ discard: continue; z = fberp(prim.v[0].p.z, prim.v[1].p.z, prim.v[2].p.z, bc); - if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) - continue; - params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + if(params->camera->enabledepth){ + if(z <= params->fb->zb[p.x + p.y*Dx(params->fb->r)]) + continue; + params->fb->zb[p.x + p.y*Dx(params->fb->r)] = z; + } /* interpolate z⁻¹ and get actual z */ z = fberp(prim.v[0].p.w, prim.v[1].p.w, prim.v[2].p.w, bc); @@ -220,7 +285,10 @@ discard: fsp.p = p; c = params->fshader(&fsp); - pixel(params->fb, p, c); + if(params->camera->enableAbuff) + pushtoAbuf(params->fb, p, c, z); + else + pixel(params->fb, p, c, params->camera->enableblend); pixeln(params->fb, p, fsp.v.n); delvattrs(&fsp.v); } @@ -249,6 +317,8 @@ rasterizer(void *arg) /* end of job */ if(params->entity == nil){ if(decref(params->job) < 1){ + if(params->job->camera->enableAbuff) + squashAbuf(params->job->fb, params->job->camera->enableblend); nbsend(params->job->donec, nil); free(params); } @@ -571,6 +641,12 @@ renderer(void *arg) continue; } + /* initialize the A-buffer */ + if(job->camera->enableAbuff){ + job->fb->abuf.stk = emalloc(Dx(job->fb->r)*Dy(job->fb->r)*sizeof(Astk)); + memset(job->fb->abuf.stk, 0, Dx(job->fb->r)*Dy(job->fb->r)*sizeof(Astk)); + } + for(ent = sc->ents.next; ent != &sc->ents; ent = ent->next){ params = emalloc(sizeof *params); memset(params, 0, sizeof *params); |