summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2024-08-10 17:57:02 +0000
committerrodri <rgl@antares-labs.eu>2024-08-10 17:57:02 +0000
commitd3b48593b0fee862ea60687336031fd9374ab667 (patch)
tree7810bcb85cbba3beee05e89b911c35f1d8e1b769
parent6eab9793d68feb3282714083b355d38c6c36400b (diff)
downloadlibgraphics-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.c1
-rw-r--r--fb.c11
-rw-r--r--graphics.h29
-rw-r--r--render.c106
4 files changed, 132 insertions, 15 deletions
diff --git a/camera.c b/camera.c
index 2a31738..8395c0e 100644
--- a/camera.c
+++ b/camera.c
@@ -126,6 +126,7 @@ newcamera(void)
c = emalloc(sizeof *c);
memset(c, 0, sizeof *c);
+ c->enabledepth = 1;
return c;
}
diff --git a/fb.c b/fb.c
index 88883fd..6bd22e9 100644
--- a/fb.c
+++ b/fb.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);
diff --git a/graphics.h b/graphics.h
index 4aa18f1..c9a7f67 100644
--- a/graphics.h
+++ b/graphics.h
@@ -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;
diff --git a/render.c b/render.c
index 41b0939..764dbca 100644
--- a/render.c
+++ b/render.c
@@ -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);