shithub: tinyrend

Download patch

ref: 25a30d016d16cfed0f35bbbafe52886e96a64e1e
parent: 97755fa8d53ac6595df5cd7c8271cd823f1a431a
author: rodri <rgl@antares-labs.eu>
date: Sun Nov 12 05:23:50 EST 2023

Lesson 2: Hidden faces removal (z-buffer)

--- a/main.c
+++ b/main.c
@@ -32,11 +32,14 @@
 
 
 Memimage *fb;
+double *zbuf;
 Memimage *red, *green, *blue;
 OBJ *model;
 Channel *drawc;
 int nprocs;
 
+char winspec[32];
+
 void resized(void);
 uvlong nanosec(void);
 
@@ -343,12 +346,13 @@
 	OBJIndexArray *idxtab;
 	Triangle3 t;
 	Triangle2 st;
+	Rectangle bbox;
 	Point3 bc;
+	static Point3 light = {0,0,-1,0}; /* global light field */
+	Point3 n;
 	int i;
 	uchar cbuf[4];
-	static Point3 light = {0,0,-1,1}; /* global point light */
-	Point3 n;
-	double intensity;
+	double z, intensity;
 
 	verts = model->vertdata[OBJVGeometric].verts;
 
@@ -365,14 +369,29 @@
 				t.p1 = Pt3(verts[idxtab->indices[1]].x,verts[idxtab->indices[1]].y,verts[idxtab->indices[1]].z,verts[idxtab->indices[1]].w);
 				t.p2 = Pt3(verts[idxtab->indices[2]].x,verts[idxtab->indices[2]].y,verts[idxtab->indices[2]].z,verts[idxtab->indices[2]].w);
 
-				st.p0 = Pt2((t.p0.x+1)*Dx(fb->r)/2, (t.p0.y+1)*Dy(fb->r)/2, 1);
-				st.p1 = Pt2((t.p1.x+1)*Dx(fb->r)/2, (t.p1.y+1)*Dy(fb->r)/2, 1);
-				st.p2 = Pt2((t.p2.x+1)*Dx(fb->r)/2, (t.p2.y+1)*Dy(fb->r)/2, 1);
+				st.p0 = Pt2((t.p0.x+1)*Dx(fb->r)/2, (-t.p0.y+1)*Dy(fb->r)/2, 1);
+				st.p1 = Pt2((t.p1.x+1)*Dx(fb->r)/2, (-t.p1.y+1)*Dy(fb->r)/2, 1);
+				st.p2 = Pt2((t.p2.x+1)*Dx(fb->r)/2, (-t.p2.y+1)*Dy(fb->r)/2, 1);
 
+				bbox = Rect(
+					min(min(st.p0.x, st.p1.x), st.p2.x), min(min(st.p0.y, st.p1.y), st.p2.y),
+					max(max(st.p0.x, st.p1.x), st.p2.x), max(max(st.p0.y, st.p1.y), st.p2.y)
+				);
+				bbox.max.x++;
+				bbox.max.y++;
+				if(!ptinrect(sp->p, bbox))
+					continue;
+
 				bc = barycoords(st, Pt2(sp->p.x,sp->p.y,1));
 				if(bc.x < 0 || bc.y < 0 || bc.z < 0)
 					continue;
 
+				z = t.p0.z*bc.x + t.p1.z*bc.y + t.p2.z*bc.z;
+
+				if(z <= zbuf[sp->p.x+sp->p.y*Dx(fb->r)])
+					continue;
+				zbuf[sp->p.x+sp->p.y*Dx(fb->r)] = z;
+
 				n = normvec3(crossvec3(subpt3(t.p2, t.p0), subpt3(t.p1, t.p0)));
 				intensity = dotvec3(n, light);
 				/* back-face culling */
@@ -391,59 +410,6 @@
 }
 
 void
-drawmodel(Memimage *dst)
-{
-	OBJObject *o;
-	OBJElem *e;
-	OBJVertex *verts;
-	OBJIndexArray *idxtab;
-	Triangle3 t;
-	Triangle st;
-	int i;
-	uchar cbuf[4];
-	static Point3 light = {0,0,-1,1}; /* global point light */
-	Point3 n;
-	double intensity;
-
-	verts = model->vertdata[OBJVGeometric].verts;
-
-	for(i = 0; i < nelem(model->objtab); i++)
-		for(o = model->objtab[i]; o != nil; o = o->next)
-			for(e = o->child; e != nil; e = e->next){
-				idxtab = &e->indextab[OBJVGeometric];
-
-				/* discard non-triangles */
-				if(e->type != OBJEFace || idxtab->nindex != 3)
-					continue;
-
-				t.p0 = Pt3(verts[idxtab->indices[0]].x,verts[idxtab->indices[0]].y,verts[idxtab->indices[0]].z,verts[idxtab->indices[0]].w);
-				t.p1 = Pt3(verts[idxtab->indices[1]].x,verts[idxtab->indices[1]].y,verts[idxtab->indices[1]].z,verts[idxtab->indices[1]].w);
-				t.p2 = Pt3(verts[idxtab->indices[2]].x,verts[idxtab->indices[2]].y,verts[idxtab->indices[2]].z,verts[idxtab->indices[2]].w);
-
-				st[0] = Pt((t.p0.x+1)*Dx(fb->r)/2, (t.p0.y+1)*Dy(fb->r)/2);
-				st[1] = Pt((t.p1.x+1)*Dx(fb->r)/2, (t.p1.y+1)*Dy(fb->r)/2);
-				st[2] = Pt((t.p2.x+1)*Dx(fb->r)/2, (t.p2.y+1)*Dy(fb->r)/2);
-
-				/* discard degenerates */
-				if(eqpt(st[0], st[1]) || eqpt(st[1], st[2]) || eqpt(st[2], st[0]))
-					continue;
-
-				n = normvec3(crossvec3(subpt3(t.p2, t.p0), subpt3(t.p1, t.p0)));
-				intensity = dotvec3(n, light);
-				/* back-face culling */
-				if(intensity < 0)
-					continue;
-
-				cbuf[0] = 0xFF;
-				cbuf[1] = 0xFF*intensity;
-				cbuf[2] = 0xFF*intensity;
-				cbuf[3] = 0xFF*intensity;
-
-				filltriangle(dst, st[0], st[1], st[2], rgb(*(ulong*)cbuf));
-			}
-}
-
-void
 redraw(void)
 {
 	lockdisplay(display);
@@ -459,15 +425,10 @@
 	uvlong t0, t1;
 
 	if(model != nil){
-//		t0 = nanosec();
-//		shade(fb, modelshader);
-//		t1 = nanosec();
-//		fprint(2, "shader took %lludns\n", t1-t0);
-
 		t0 = nanosec();
-		drawmodel(fb);
+		shade(fb, modelshader);
 		t1 = nanosec();
-		fprint(2, "drawmodel took %lludns\n", t1-t0);
+		fprint(2, "shader took %lludns\n", t1-t0);
 	}else{
 		t0 = nanosec();
 		shade(fb, circleshader);
@@ -553,7 +514,8 @@
 	if(nprocs < 1)
 		nprocs = strtoul(getenv("NPROC"), nil, 10);
 
-	if(newwindow(nil) < 0)
+	snprint(winspec, sizeof winspec, "-dx %d -dy %d", 800, 800);
+	if(newwindow(winspec) < 0)
 		sysfatal("newwindow: %r");
 	if(initdraw(nil, nil, "tinyrend") < 0)
 		sysfatal("initdraw: %r");
@@ -565,15 +527,14 @@
 		sysfatal("initkeyboard: %r");
 
 	fb = eallocmemimage(rectsubpt(screen->r, screen->r.min), screen->chan);
+	zbuf = emalloc(Dx(fb->r)*Dy(fb->r)*sizeof(double));
+	memset(zbuf, ~0, Dx(fb->r)*Dy(fb->r)*sizeof(double));
 	red = rgb(DRed);
 	green = rgb(DGreen);
 	blue = rgb(DBlue);
 
-	if(mdlpath != nil){
-		model = objparse(mdlpath);
-		if(model == nil)
-			sysfatal("objparse: %r");
-	}
+	if(mdlpath != nil && (model = objparse(mdlpath)) == nil)
+		sysfatal("objparse: %r");
 
 	render();