shithub: libgraphics

Download patch

ref: b41192ebe4f5f0720cf7e4dc5ca1f6fc0131daf1
parent: a101d22599c9052ab242d68e12522732e710cc9e
author: rodri <rgl@antares-labs.eu>
date: Mon Apr 15 22:48:01 EDT 2024

replace the Triangle with a general purpose Primitive.

this is only an structural replacement and doesn't add
support for the other primitive types.

--- a/fb.c
+++ b/fb.c
@@ -45,7 +45,7 @@
 
 	/* address the back buffer—resetting the front buffer is VERBOTEN */
 	fb = ctl->getbb(ctl);
-	memsetd(fb->zbuf, Inf(-1), Dx(fb->r)*Dy(fb->r));
+	memsetd(fb->zb, Inf(-1), Dx(fb->r)*Dy(fb->r));
 	memfillcolor(fb->cb, DTransparent);
 }
 
@@ -69,8 +69,8 @@
 	fb = emalloc(sizeof *fb);
 	memset(fb, 0, sizeof *fb);
 	fb->cb = eallocmemimage(r, RGBA32);
-	fb->zbuf = emalloc(Dx(r)*Dy(r)*sizeof(*fb->zbuf));
-	memsetd(fb->zbuf, Inf(-1), Dx(r)*Dy(r));
+	fb->zb = emalloc(Dx(r)*Dy(r)*sizeof(*fb->zb));
+	memsetd(fb->zb, Inf(-1), Dx(r)*Dy(r));
 	fb->r = r;
 	return fb;
 }
@@ -78,7 +78,7 @@
 void
 rmfb(Framebuf *fb)
 {
-	free(fb->zbuf);
+	free(fb->zb);
 	freememimage(fb->cb);
 	free(fb);
 }
--- a/graphics.h
+++ b/graphics.h
@@ -2,10 +2,16 @@
 
 typedef enum {
 	ORTHOGRAPHIC,
-	PERSPECTIVE
+	PERSPECTIVE,
 } Projection;
 
 enum {
+	PPoint,
+	PLine,
+	PTriangle,
+};
+
+enum {
 	LIGHT_POINT,
 	LIGHT_DIRECTIONAL,
 	LIGHT_SPOT,
@@ -21,6 +27,7 @@
 typedef struct Vertex Vertex;
 typedef struct LightSource LightSource;
 typedef struct Material Material;
+typedef struct Primitive Primitive;
 typedef struct Model Model;
 typedef struct Entity Entity;
 typedef struct Scene Scene;
@@ -86,8 +93,6 @@
 	ulong nattrs;
 };
 
-typedef Vertex Triangle[3];
-
 struct LightSource
 {
 	Point3 p;
@@ -103,16 +108,22 @@
 	double shininess;
 };
 
+struct Primitive
+{
+	int type;
+	Vertex v[3];
+};
+
 struct Model
 {
-	OBJ *obj;
+	Primitive *mesh;
 	Memimage *tex;		/* texture map */
 	Memimage *nor;		/* normals map */
 	Material *materials;
 	ulong nmaterials;
 
-	/* cache of renderable elems */
-	OBJElem **elems;
+	OBJ *obj;
+	OBJElem **elems;	/* cache of renderable elems */
 	ulong nelems;
 };
 
@@ -190,7 +201,7 @@
 	Channel *donec;
 
 	struct {
-		Rendertime R, E, Tn, Rn;
+		Rendertime R, E, Tn, Rn;	/* renderer, entityproc, tilers, rasterizers */
 	} times;
 
 	Renderjob *next;
@@ -199,7 +210,7 @@
 struct Framebuf
 {
 	Memimage *cb;	/* color buffer */
-	double *zbuf;	/* z/depth buffer */
+	double *zb;	/* z/depth buffer */
 	Rectangle r;
 };
 
--- a/internal.h
+++ b/internal.h
@@ -5,7 +5,7 @@
 {
 	SUparams *params;
 	Rectangle wr;		/* working rect */
-	Triangle t;
+	Primitive p;
 };
 
 struct Tilerparam
--- a/render.c
+++ b/render.c
@@ -42,13 +42,13 @@
 }
 
 static int
-isfacingback(Triangle t)
+isfacingback(Primitive p)
 {
 	double sa;	/* signed area */
 
-	sa = t[0].p.x * t[1].p.y - t[0].p.y * t[1].p.x +
-	     t[1].p.x * t[2].p.y - t[1].p.y * t[2].p.x +
-	     t[2].p.x * t[0].p.y - t[2].p.y * t[0].p.x;
+	sa = p.v[0].p.x * p.v[1].p.y - p.v[0].p.y * p.v[1].p.x +
+	     p.v[1].p.x * p.v[2].p.y - p.v[1].p.y * p.v[2].p.x +
+	     p.v[2].p.x * p.v[0].p.y - p.v[2].p.y * p.v[0].p.x;
 	return sa <= 0;
 }
 
@@ -105,7 +105,7 @@
  * 	- https://github.com/aap/librw/blob/14dab85dcae6f3762fb2b1eda4d58d8e67541330/tools/playground/tl_tests.cpp#L522
  */
 static int
-cliptriangle(Triangle *t)
+cliptriangle(Primitive *p)
 {
 	/* signed distance from each clipping plane */
 	static double sdm[6][4] = {
@@ -126,7 +126,7 @@
 	memset(&Vin, 0, sizeof Vin);
 	memset(&Vout, 0, sizeof Vout);
 	for(i = 0; i < 3; i++)
-		addvert(&Vin, t[0][i]);
+		addvert(&Vin, p[0].v[i]);
 
 	for(j = 0; j < 6 && Vin.n > 0; j++){
 		for(i = 0; i < Vin.n; i++){
@@ -169,9 +169,9 @@
 			 * are referenced on every triangle, so duplicate them
 			 * to avoid complications during rasterization.
 			 */
-			t[nt][0] = i < Vout.n-2-1? dupvertex(&Vout.v[0]): Vout.v[0];
-			t[nt][1] = Vout.v[i+1];
-			t[nt][2] = i < Vout.n-2-1? dupvertex(&Vout.v[i+2]): Vout.v[i+2];
+			p[nt].v[0] = i < Vout.n-2-1? dupvertex(&Vout.v[0]): Vout.v[0];
+			p[nt].v[1] = Vout.v[i+1];
+			p[nt].v[2] = i < Vout.n-2-1? dupvertex(&Vout.v[i+2]): Vout.v[i+2];
 		}
 	free(Vout.v);
 	free(Vin.v);
@@ -295,7 +295,7 @@
 rasterize(Rastertask *task)
 {
 	SUparams *params;
-	Triangle t;
+	Primitive prim;
 	FSparams fsp;
 	Triangle2 t₂;
 	Rectangle bbox;
@@ -305,11 +305,12 @@
 	double z, depth;
 
 	params = task->params;
-	memmove(t, task->t, sizeof t);
+	prim = task->p;
+	memmove(prim.v, task->p.v, sizeof prim.v);
 
-	t₂.p0 = Pt2(t[0].p.x, t[0].p.y, 1);
-	t₂.p1 = Pt2(t[1].p.x, t[1].p.y, 1);
-	t₂.p2 = Pt2(t[2].p.x, t[2].p.y, 1);
+	t₂.p0 = Pt2(prim.v[0].p.x, prim.v[0].p.y, 1);
+	t₂.p1 = Pt2(prim.v[1].p.x, prim.v[1].p.y, 1);
+	t₂.p2 = Pt2(prim.v[2].p.x, prim.v[2].p.y, 1);
 	/* find the triangle's bbox and clip it against the fb */
 	bbox = Rect(
 		min(min(t₂.p0.x, t₂.p1.x), t₂.p2.x), min(min(t₂.p0.y, t₂.p1.y), t₂.p2.y),
@@ -328,22 +329,22 @@
 			if(bc.x < 0 || bc.y < 0 || bc.z < 0)
 				continue;
 
-			z = fberp(t[0].p.z, t[1].p.z, t[2].p.z, bc);
+			z = fberp(prim.v[0].p.z, prim.v[1].p.z, prim.v[2].p.z, bc);
 			depth = fclamp(z, 0, 1);
-			if(depth <= params->fb->zbuf[p.x + p.y*Dx(params->fb->r)])
+			if(depth <= params->fb->zb[p.x + p.y*Dx(params->fb->r)])
 				continue;
-			params->fb->zbuf[p.x + p.y*Dx(params->fb->r)] = depth;
+			params->fb->zb[p.x + p.y*Dx(params->fb->r)] = depth;
 
 			/* interpolate z⁻¹ and get actual z */
-			z = fberp(t[0].p.w, t[1].p.w, t[2].p.w, bc);
+			z = fberp(prim.v[0].p.w, prim.v[1].p.w, prim.v[2].p.w, bc);
 			z = 1.0/(z < 1e-5? 1e-5: z);
 
 			/* perspective-correct attribute interpolation  */
-			bc.x *= t[0].p.w;
-			bc.y *= t[1].p.w;
-			bc.z *= t[2].p.w;
+			bc.x *= prim.v[0].p.w;
+			bc.y *= prim.v[1].p.w;
+			bc.z *= prim.v[2].p.w;
 			bc = mulpt3(bc, z);
-			berpvertex(&fsp.v, &t[0], &t[1], &t[2], bc);
+			berpvertex(&fsp.v, &prim.v[0], &prim.v[1], &prim.v[2], bc);
 
 			fsp.p = p;
 			c = params->fshader(&fsp);
@@ -388,9 +389,9 @@
 		params->frag = frag;
 		rasterize(task);
 
-		delvattrs(&task->t[0]);
-		delvattrs(&task->t[1]);
-		delvattrs(&task->t[2]);
+		delvattrs(&task->p.v[0]);
+		delvattrs(&task->p.v[1]);
+		delvattrs(&task->p.v[2]);
 		params->job->times.Rn.t1 = nanosec();
 		free(params);
 		free(task);
@@ -408,17 +409,17 @@
 	OBJIndexArray *idxtab;
 	OBJElem **ep;
 	Point3 n;				/* surface normal */
-	Triangle *t;				/* triangles to raster */
+	Primitive *p;				/* primitives to raster */
 	Rectangle *wr;
 	Channel **taskc;
 	ulong Δy, nproc;
-	int i, nt;
+	int i, np;
 	uvlong t0;
 
 	threadsetname("tilerdurden");
 
 	tp = arg;
-	t = emalloc(sizeof(*t)*16);
+	p = emalloc(sizeof(*p)*16);
 	taskc = tp->tasksc;
 	nproc = tp->nproc;
 	wr = emalloc(nproc*sizeof(Rectangle));
@@ -454,105 +455,107 @@
 		nverts = params->entity->mdl->obj->vertdata[OBJVNormal].verts;
 
 		for(ep = params->eb; ep != params->ee; ep++){
-			nt = 1;	/* start with one. after clipping it might change */
+			np = 1;	/* start with one. after clipping it might change */
 
+			/* TODO handle all the primitive types */
+
 			idxtab = &(*ep)->indextab[OBJVGeometric];
-			t[0][0].p = Pt3(verts[idxtab->indices[0]].x,
-					verts[idxtab->indices[0]].y,
-					verts[idxtab->indices[0]].z,
-					verts[idxtab->indices[0]].w);
-			t[0][1].p = Pt3(verts[idxtab->indices[1]].x,
-					verts[idxtab->indices[1]].y,
-					verts[idxtab->indices[1]].z,
-					verts[idxtab->indices[1]].w);
-			t[0][2].p = Pt3(verts[idxtab->indices[2]].x,
-					verts[idxtab->indices[2]].y,
-					verts[idxtab->indices[2]].z,
-					verts[idxtab->indices[2]].w);
+			p[0].v[0].p = Pt3(verts[idxtab->indices[0]].x,
+					  verts[idxtab->indices[0]].y,
+					  verts[idxtab->indices[0]].z,
+					  verts[idxtab->indices[0]].w);
+			p[0].v[1].p = Pt3(verts[idxtab->indices[1]].x,
+					  verts[idxtab->indices[1]].y,
+					  verts[idxtab->indices[1]].z,
+					  verts[idxtab->indices[1]].w);
+			p[0].v[2].p = Pt3(verts[idxtab->indices[2]].x,
+					  verts[idxtab->indices[2]].y,
+					  verts[idxtab->indices[2]].z,
+					  verts[idxtab->indices[2]].w);
 
 			idxtab = &(*ep)->indextab[OBJVNormal];
 			if(idxtab->nindex == 3){
-				t[0][0].n = Vec3(nverts[idxtab->indices[0]].i,
-						 nverts[idxtab->indices[0]].j,
-						 nverts[idxtab->indices[0]].k);
-				t[0][0].n = normvec3(t[0][0].n);
-				t[0][1].n = Vec3(nverts[idxtab->indices[1]].i,
-						 nverts[idxtab->indices[1]].j,
-						 nverts[idxtab->indices[1]].k);
-				t[0][1].n = normvec3(t[0][1].n);
-				t[0][2].n = Vec3(nverts[idxtab->indices[2]].i,
-						 nverts[idxtab->indices[2]].j,
-						 nverts[idxtab->indices[2]].k);
-				t[0][2].n = normvec3(t[0][2].n);
+				p[0].v[0].n = Vec3(nverts[idxtab->indices[0]].i,
+						   nverts[idxtab->indices[0]].j,
+						   nverts[idxtab->indices[0]].k);
+				p[0].v[0].n = normvec3(p[0].v[0].n);
+				p[0].v[1].n = Vec3(nverts[idxtab->indices[1]].i,
+						   nverts[idxtab->indices[1]].j,
+						   nverts[idxtab->indices[1]].k);
+				p[0].v[1].n = normvec3(p[0].v[1].n);
+				p[0].v[2].n = Vec3(nverts[idxtab->indices[2]].i,
+						   nverts[idxtab->indices[2]].j,
+						   nverts[idxtab->indices[2]].k);
+				p[0].v[2].n = normvec3(p[0].v[2].n);
 			}else{
 				/* TODO build a list of per-vertex normals earlier */
-				n = normvec3(crossvec3(subpt3(t[0][1].p, t[0][0].p), subpt3(t[0][2].p, t[0][0].p)));
-				t[0][0].n = t[0][1].n = t[0][2].n = n;
+				n = normvec3(crossvec3(subpt3(p[0].v[1].p, p[0].v[0].p), subpt3(p[0].v[2].p, p[0].v[0].p)));
+				p[0].v[0].n = p[0].v[1].n = p[0].v[2].n = n;
 			}
 
 			idxtab = &(*ep)->indextab[OBJVTexture];
 			if(idxtab->nindex == 3){
-				t[0][0].uv = Pt2(tverts[idxtab->indices[0]].u,
-						 tverts[idxtab->indices[0]].v, 1);
-				t[0][1].uv = Pt2(tverts[idxtab->indices[1]].u,
-						 tverts[idxtab->indices[1]].v, 1);
-				t[0][2].uv = Pt2(tverts[idxtab->indices[2]].u,
-						 tverts[idxtab->indices[2]].v, 1);
+				p[0].v[0].uv = Pt2(tverts[idxtab->indices[0]].u,
+						   tverts[idxtab->indices[0]].v, 1);
+				p[0].v[1].uv = Pt2(tverts[idxtab->indices[1]].u,
+						   tverts[idxtab->indices[1]].v, 1);
+				p[0].v[2].uv = Pt2(tverts[idxtab->indices[2]].u,
+						   tverts[idxtab->indices[2]].v, 1);
 			}else{
-				t[0][0].uv = t[0][1].uv = t[0][2].uv = Vec2(0,0);
+				p[0].v[0].uv = p[0].v[1].uv = p[0].v[2].uv = Vec2(0,0);
 			}
 
 			for(i = 0; i < 3; i++){
-				t[0][i].c = Pt3(1,1,1,1);
-				t[0][i].mtl = (*ep)->mtl;
-				t[0][i].attrs = nil;
-				t[0][i].nattrs = 0;
+				p[0].v[i].c = Pt3(1,1,1,1);
+				p[0].v[i].mtl = (*ep)->mtl;
+				p[0].v[i].attrs = nil;
+				p[0].v[i].nattrs = 0;
 			}
 
-			vsp.v = &t[0][0];
+			vsp.v = &p[0].v[0];
 			vsp.idx = 0;
-			t[0][0].p = params->vshader(&vsp);
-			vsp.v = &t[0][1];
+			p[0].v[0].p = params->vshader(&vsp);
+			vsp.v = &p[0].v[1];
 			vsp.idx = 1;
-			t[0][1].p = params->vshader(&vsp);
-			vsp.v = &t[0][2];
+			p[0].v[1].p = params->vshader(&vsp);
+			vsp.v = &p[0].v[2];
 			vsp.idx = 2;
-			t[0][2].p = params->vshader(&vsp);
+			p[0].v[2].p = params->vshader(&vsp);
 
-			if(!isvisible(t[0][0].p) || !isvisible(t[0][1].p) || !isvisible(t[0][2].p))
-				nt = cliptriangle(t);
+			if(!isvisible(p[0].v[0].p) || !isvisible(p[0].v[1].p) || !isvisible(p[0].v[2].p))
+				np = cliptriangle(p);
 
-			while(nt--){
-				t[nt][0].p = clip2ndc(t[nt][0].p);
-				t[nt][1].p = clip2ndc(t[nt][1].p);
-				t[nt][2].p = clip2ndc(t[nt][2].p);
+			while(np--){
+				p[np].v[0].p = clip2ndc(p[np].v[0].p);
+				p[np].v[1].p = clip2ndc(p[np].v[1].p);
+				p[np].v[2].p = clip2ndc(p[np].v[2].p);
 
 				/* culling */
-//				if(isfacingback(t[nt]))
+//				if(isfacingback(p[np]))
 //					goto skiptri;
 
-				t[nt][0].p = ndc2viewport(params->fb, t[nt][0].p);
-				t[nt][1].p = ndc2viewport(params->fb, t[nt][1].p);
-				t[nt][2].p = ndc2viewport(params->fb, t[nt][2].p);
+				p[np].v[0].p = ndc2viewport(params->fb, p[np].v[0].p);
+				p[np].v[1].p = ndc2viewport(params->fb, p[np].v[1].p);
+				p[np].v[2].p = ndc2viewport(params->fb, p[np].v[2].p);
 
 				for(i = 0; i < nproc; i++)
-					if(ptinrect(Pt(t[nt][0].p.x,t[nt][0].p.y),wr[i]) ||
-					   ptinrect(Pt(t[nt][1].p.x,t[nt][1].p.y),wr[i]) ||
-					   ptinrect(Pt(t[nt][2].p.x,t[nt][2].p.y),wr[i])){
+					if(ptinrect(Pt(p[np].v[0].p.x,p[np].v[0].p.y),wr[i]) ||
+					   ptinrect(Pt(p[np].v[1].p.x,p[np].v[1].p.y),wr[i]) ||
+					   ptinrect(Pt(p[np].v[2].p.x,p[np].v[2].p.y),wr[i])){
 						newparams = emalloc(sizeof *newparams);
 						*newparams = *params;
 						task = emalloc(sizeof *task);
 						task->params = newparams;
 						task->wr = wr[i];
-						task->t[0] = dupvertex(&t[nt][0]);
-						task->t[1] = dupvertex(&t[nt][1]);
-						task->t[2] = dupvertex(&t[nt][2]);
+						task->p.v[0] = dupvertex(&p[np].v[0]);
+						task->p.v[1] = dupvertex(&p[np].v[1]);
+						task->p.v[2] = dupvertex(&p[np].v[2]);
 						sendp(taskc[i], task);
 					}
 //skiptri:
-				delvattrs(&t[nt][0]);
-				delvattrs(&t[nt][1]);
-				delvattrs(&t[nt][2]);
+				delvattrs(&p[np].v[0]);
+				delvattrs(&p[np].v[1]);
+				delvattrs(&p[np].v[2]);
 			}
 		}
 		params->job->times.Tn.t1 = nanosec();