shithub: libgraphics

Download patch

ref: 5b93335dd430e09a71ebaba131826cd7db154cb4
parent: e90bf70b0d7167166a3c84e4f3e9277ce4a7e97a
author: rodri <rgl@antares-labs.eu>
date: Tue Feb 13 11:40:31 EST 2024

lay out the grounds for a scene renderer.

also fixed an issue with cliptriangle() where an
entire tri would get discarded if all its vertices
were outside the frustum.

--- a/camera.c
+++ b/camera.c
@@ -78,14 +78,13 @@
 }
 
 void
-shootcamera(Camera *c, OBJ *m, Memimage *tex, Shader *s)
+shootcamera(Camera *c, Shader *s)
 {
 	uvlong t0, t1;
 
 	c->vp->fbctl->reset(c->vp->fbctl);
 	t0 = nanosec();
-	/* TODO let the user choose the nproc value (left at 1 for now) */
-	shade(c->vp->fbctl->fb[c->vp->fbctl->idx^1], m, tex, s, 1);	/* address the back buffer */
+	shade(c->vp->fbctl->fb[c->vp->fbctl->idx^1], c->s, s);	/* address the back buffer */
 	t1 = nanosec();
 	c->vp->fbctl->swap(c->vp->fbctl);
 
--- a/graphics.h
+++ b/graphics.h
@@ -16,7 +16,7 @@
 typedef struct Material Material;
 typedef struct Model Model;
 typedef struct Entity Entity;
-typedef struct Environment Environment;
+typedef struct Scene Scene;
 typedef struct VSparams VSparams;
 typedef struct FSparams FSparams;
 typedef struct SUparams SUparams;
@@ -56,20 +56,30 @@
 
 struct Model
 {
+	OBJ *obj;
+	Memimage *tex;
 	Material *materials;
 	ulong nmaterials;
+
+	/* cache of renderable elems */
+	OBJElem **elems;
+	ulong nelems;
 };
 
 struct Entity
 {
+	RFrame3;
 	Model *mdl;
+	Entity *prev, *next;
 };
 
 struct Scene
 {
-	Entity **ents;
+	char *name;
+	Entity ents;
 	ulong nents;
-	
+
+	void (*addent)(Scene*, Entity*);
 };
 
 /* shader params */
@@ -93,13 +103,11 @@
 struct SUparams
 {
 	Framebuf *fb;
-	OBJElem **b, **e;
 	int id;
 	Channel *donec;
 
 	/* TODO replace with a Scene */
-	OBJ *model;
-	Memimage *modeltex;
+	Model *model;
 
 	double var_intensity[3];
 
@@ -145,6 +153,7 @@
 {
 	RFrame3;		/* VCS */
 	Viewport *vp;
+	Scene *s;
 	double fov;		/* vertical FOV */
 	struct {
 		double n, f;	/* near and far clipping planes */
@@ -162,7 +171,7 @@
 void placecamera(Camera*, Point3, Point3, Point3);
 void aimcamera(Camera*, Point3);
 void reloadcamera(Camera*);
-void shootcamera(Camera*, OBJ*, Memimage*, Shader*);
+void shootcamera(Camera*, Shader*);
 
 /* viewport */
 Viewport *mkviewport(Rectangle);
@@ -174,6 +183,15 @@
 Point3 world2clip(Camera*, Point3);
 void perspective(Matrix3, double, double, double, double);
 void orthographic(Matrix3, double, double, double, double, double, double);
+
+/* scene */
+int refreshmodel(Model*);
+Model *newmodel(void);
+void delmodel(Model*);
+Entity *newentity(Model*);
+void delentity(Entity*);
+Scene *newscene(char*);
+void delscene(Scene*);
 
 /* util */
 double fmin(double, double);
--- a/internal.h
+++ b/internal.h
@@ -10,7 +10,7 @@
 void rmfbctl(Framebufctl*);
 
 /* render */
-void shade(Framebuf*, OBJ*, Memimage*, Shader*, ulong);
+void shade(Framebuf*, Scene*, Shader*);
 
 /* util */
 int min(int, int);
--- a/mkfile
+++ b/mkfile
@@ -5,6 +5,7 @@
 	camera.$O\
 	viewport.$O\
 	render.$O\
+	scene.$O\
 	alloc.$O\
 	fb.$O\
 	shadeop.$O\
--- a/render.c
+++ b/render.c
@@ -20,75 +20,7 @@
 	memimagedraw(dst, rectaddpt(UR, p), src, ZP, nil, ZP, SoverD);
 }
 
-/*
- * it only processes quads for now.
- */
 static int
-triangulate(OBJElem **newe, OBJElem *e)
-{
-	OBJIndexArray *newidxtab;
-	OBJIndexArray *idxtab;
-
-	idxtab = &e->indextab[OBJVGeometric];
-	newe[0] = emalloc(sizeof **newe);
-	newe[0]->type = OBJEFace;
-	newidxtab = &newe[0]->indextab[OBJVGeometric];
-	newidxtab->nindex = 3;
-	newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
-	newidxtab->indices[0] = idxtab->indices[0];
-	newidxtab->indices[1] = idxtab->indices[1];
-	newidxtab->indices[2] = idxtab->indices[2];
-	idxtab = &e->indextab[OBJVTexture];
-	if(idxtab->nindex > 0){
-		newidxtab = &newe[0]->indextab[OBJVTexture];
-		newidxtab->nindex = 3;
-		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
-		newidxtab->indices[0] = idxtab->indices[0];
-		newidxtab->indices[1] = idxtab->indices[1];
-		newidxtab->indices[2] = idxtab->indices[2];
-	}
-	idxtab = &e->indextab[OBJVNormal];
-	if(idxtab->nindex > 0){
-		newidxtab = &newe[0]->indextab[OBJVNormal];
-		newidxtab->nindex = 3;
-		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
-		newidxtab->indices[0] = idxtab->indices[0];
-		newidxtab->indices[1] = idxtab->indices[1];
-		newidxtab->indices[2] = idxtab->indices[2];
-	}
-
-	idxtab = &e->indextab[OBJVGeometric];
-	newe[1] = emalloc(sizeof **newe);
-	newe[1]->type = OBJEFace;
-	newidxtab = &newe[1]->indextab[OBJVGeometric];
-	newidxtab->nindex = 3;
-	newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
-	newidxtab->indices[0] = idxtab->indices[0];
-	newidxtab->indices[1] = idxtab->indices[2];
-	newidxtab->indices[2] = idxtab->indices[3];
-	idxtab = &e->indextab[OBJVTexture];
-	if(idxtab->nindex > 0){
-		newidxtab = &newe[1]->indextab[OBJVTexture];
-		newidxtab->nindex = 3;
-		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
-		newidxtab->indices[0] = idxtab->indices[0];
-		newidxtab->indices[1] = idxtab->indices[2];
-		newidxtab->indices[2] = idxtab->indices[3];
-	}
-	idxtab = &e->indextab[OBJVNormal];
-	if(idxtab->nindex > 0){
-		newidxtab = &newe[1]->indextab[OBJVNormal];
-		newidxtab->nindex = 3;
-		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
-		newidxtab->indices[0] = idxtab->indices[0];
-		newidxtab->indices[1] = idxtab->indices[2];
-		newidxtab->indices[2] = idxtab->indices[3];
-	}
-
-	return 2;
-}
-
-static int
 isvisible(Point3 p)
 {
 	if(p.x < -p.w || p.x > p.w ||
@@ -157,9 +89,6 @@
 	Vertex *v0, *v1, v;	/* edge verts and new vertex (line-plane intersection) */
 	int i, j, nt;
 
-	if(!isvisible(t[0][0].p) && !isvisible(t[0][1].p) && !isvisible(t[0][2].p))
-		return 0;
-
 	nt = 0;
 	memset(&Vin, 0, sizeof Vin);
 	memset(&Vout, 0, sizeof Vout);
@@ -388,19 +317,19 @@
 				tt₂.p1 = mulpt2(t[1].uv, bc.y*z);
 				tt₂.p2 = mulpt2(t[2].uv, bc.z*z);
 
-				tp.x = (tt₂.p0.x + tt₂.p1.x + tt₂.p2.x)*Dx(params->modeltex->r);
-				tp.y = (1 - (tt₂.p0.y + tt₂.p1.y + tt₂.p2.y))*Dy(params->modeltex->r);
+				tp.x = (tt₂.p0.x + tt₂.p1.x + tt₂.p2.x)*Dx(params->model->tex->r);
+				tp.y = (1 - (tt₂.p0.y + tt₂.p1.y + tt₂.p2.y))*Dy(params->model->tex->r);
 
-				switch(params->modeltex->chan){
+				switch(params->model->tex->chan){
 				case RGB24:
-					unloadmemimage(params->modeltex, rectaddpt(UR, tp), cbuf+1, sizeof cbuf - 1);
+					unloadmemimage(params->model->tex, rectaddpt(UR, tp), cbuf+1, sizeof cbuf - 1);
 					cbuf[0] = 0xFF;
 					break;
 				case RGBA32:
-					unloadmemimage(params->modeltex, rectaddpt(UR, tp), cbuf, sizeof cbuf);
+					unloadmemimage(params->model->tex, rectaddpt(UR, tp), cbuf, sizeof cbuf);
 					break;
 				case XRGB32:
-					unloadmemimage(params->modeltex, rectaddpt(UR, tp), cbuf, sizeof cbuf);
+					unloadmemimage(params->model->tex, rectaddpt(UR, tp), cbuf, sizeof cbuf);
 					memmove(cbuf+1, cbuf, 3);
 					cbuf[0] = 0xFF;
 					break;
@@ -425,7 +354,7 @@
 	Memimage *frag;
 	OBJVertex *verts, *tverts, *nverts;	/* geometric, texture and normals vertices */
 	OBJIndexArray *idxtab;
-	OBJElem **ep;
+	OBJElem **ep, **eb, **ee;
 	Point3 n;				/* surface normal */
 	Triangle *t;				/* triangles to raster */
 	int nt;
@@ -437,11 +366,13 @@
 	threadsetname("shader unit #%d", params->id);
 
 	t = emalloc(sizeof(*t)*16);
-	verts = params->model->vertdata[OBJVGeometric].verts;
-	tverts = params->model->vertdata[OBJVTexture].verts;
-	nverts = params->model->vertdata[OBJVNormal].verts;
+	verts = params->model->obj->vertdata[OBJVGeometric].verts;
+	tverts = params->model->obj->vertdata[OBJVTexture].verts;
+	nverts = params->model->obj->vertdata[OBJVNormal].verts;
+	eb = params->model->elems;
+	ee = eb + params->model->nelems;
 
-	for(ep = params->b; ep != params->e; ep++){
+	for(ep = eb; ep != ee; ep++){
 		nt = 1;	/* start with one. after clipping it might change */
 
 		idxtab = &(*ep)->indextab[OBJVGeometric];
@@ -464,7 +395,7 @@
 		}
 
 		idxtab = &(*ep)->indextab[OBJVTexture];
-		if(params->modeltex != nil && idxtab->nindex == 3){
+		if(params->model->tex != nil && 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);
@@ -502,65 +433,28 @@
 }
 
 void
-shade(Framebuf *fb, OBJ *model, Memimage *modeltex, Shader *s, ulong nprocs)
+shade(Framebuf *fb, Scene *sc, Shader *s)
 {
-	static int nparts, nworkers;
-	static OBJElem **elems = nil;
-	OBJElem *trielems[2];
-	int i, nelems;
+	int i;
 	uvlong time;
-	OBJObject *o;
-	OBJElem *e;
-	OBJIndexArray *idxtab;
+	Entity *ent;
 	SUparams *params;
 	Channel *donec;
 
-	if(elems == nil){
-		nelems = 0;
-		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 && idxtab->nindex != 4))
-						continue;
-					if(idxtab->nindex == 4){
-						triangulate(trielems, e);
-						nelems += 2;
-						elems = erealloc(elems, nelems*sizeof(*elems));
-						elems[nelems-2] = trielems[0];
-						elems[nelems-1] = trielems[1];
-					}else{
-						elems = erealloc(elems, ++nelems*sizeof(*elems));
-						elems[nelems-1] = e;
-					}
-				}
-		if(nelems < nprocs){
-			nworkers = nelems;
-			nparts = 1;
-		}else{
-			nworkers = nprocs;
-			nparts = nelems/nprocs;
-		}
-	}
 	time = nanosec();
-
 	donec = chancreate(sizeof(void*), 0);
 
-	for(i = 0; i < nworkers; i++){
+	/* TODO come up with an actual concurrent architecture */
+	for(i = 0, ent = sc->ents.next; i < sc->nents; i++, ent = ent->next){
 		params = emalloc(sizeof *params);
 		params->fb = fb;
-		params->b = &elems[i*nparts];
-		params->e = params->b + nparts;
 		params->id = i;
 		params->donec = donec;
-		params->model = model;
-		params->modeltex = modeltex;
+		params->model = ent->mdl;
 		params->uni_time = time;
 		params->vshader = s->vshader;
 		params->fshader = s->fshader;
 		proccreate(shaderunit, params, mainstacksize);
-//		fprint(2, "spawned su %d for elems [%d, %d)\n", params->id, i*nparts, i*nparts+nparts);
 	}
 
 	while(i--)
--- /dev/null
+++ b/scene.c
@@ -1,0 +1,185 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <geometry.h>
+#include "libobj/obj.h"
+#include "graphics.h"
+#include "internal.h"
+
+/*
+ * it only processes quads for now.
+ */
+static int
+triangulate(OBJElem **newe, OBJElem *e)
+{
+	OBJIndexArray *newidxtab;
+	OBJIndexArray *idxtab;
+
+	idxtab = &e->indextab[OBJVGeometric];
+	newe[0] = emalloc(sizeof **newe);
+	newe[0]->type = OBJEFace;
+	newidxtab = &newe[0]->indextab[OBJVGeometric];
+	newidxtab->nindex = 3;
+	newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+	newidxtab->indices[0] = idxtab->indices[0];
+	newidxtab->indices[1] = idxtab->indices[1];
+	newidxtab->indices[2] = idxtab->indices[2];
+	idxtab = &e->indextab[OBJVTexture];
+	if(idxtab->nindex > 0){
+		newidxtab = &newe[0]->indextab[OBJVTexture];
+		newidxtab->nindex = 3;
+		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+		newidxtab->indices[0] = idxtab->indices[0];
+		newidxtab->indices[1] = idxtab->indices[1];
+		newidxtab->indices[2] = idxtab->indices[2];
+	}
+	idxtab = &e->indextab[OBJVNormal];
+	if(idxtab->nindex > 0){
+		newidxtab = &newe[0]->indextab[OBJVNormal];
+		newidxtab->nindex = 3;
+		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+		newidxtab->indices[0] = idxtab->indices[0];
+		newidxtab->indices[1] = idxtab->indices[1];
+		newidxtab->indices[2] = idxtab->indices[2];
+	}
+
+	idxtab = &e->indextab[OBJVGeometric];
+	newe[1] = emalloc(sizeof **newe);
+	newe[1]->type = OBJEFace;
+	newidxtab = &newe[1]->indextab[OBJVGeometric];
+	newidxtab->nindex = 3;
+	newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+	newidxtab->indices[0] = idxtab->indices[0];
+	newidxtab->indices[1] = idxtab->indices[2];
+	newidxtab->indices[2] = idxtab->indices[3];
+	idxtab = &e->indextab[OBJVTexture];
+	if(idxtab->nindex > 0){
+		newidxtab = &newe[1]->indextab[OBJVTexture];
+		newidxtab->nindex = 3;
+		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+		newidxtab->indices[0] = idxtab->indices[0];
+		newidxtab->indices[1] = idxtab->indices[2];
+		newidxtab->indices[2] = idxtab->indices[3];
+	}
+	idxtab = &e->indextab[OBJVNormal];
+	if(idxtab->nindex > 0){
+		newidxtab = &newe[1]->indextab[OBJVNormal];
+		newidxtab->nindex = 3;
+		newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+		newidxtab->indices[0] = idxtab->indices[0];
+		newidxtab->indices[1] = idxtab->indices[2];
+		newidxtab->indices[2] = idxtab->indices[3];
+	}
+
+	return 2;
+}
+
+/*
+ * rebuild the cache of renderable OBJElems.
+ *
+ * run it every time the Model's geometry changes.
+ */
+int
+refreshmodel(Model *m)
+{
+	OBJElem *trielems[2];
+	OBJObject *o;
+	OBJElem *e;
+	OBJIndexArray *idxtab;
+	int i;
+
+	if(m->elems != nil){
+		free(m->elems);
+		m->elems = nil;
+	}
+	m->nelems = 0;
+	for(i = 0; i < nelem(m->obj->objtab); i++)
+		for(o = m->obj->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 && idxtab->nindex != 4))
+					continue;
+				if(idxtab->nindex == 4){
+					triangulate(trielems, e);
+					m->nelems += 2;
+					m->elems = erealloc(m->elems, m->nelems*sizeof(*m->elems));
+					m->elems[m->nelems-2] = trielems[0];
+					m->elems[m->nelems-1] = trielems[1];
+				}else{
+					m->elems = erealloc(m->elems, ++m->nelems*sizeof(*m->elems));
+					m->elems[m->nelems-1] = e;
+				}
+			}
+	return m->nelems;
+}
+
+Model *
+newmodel(void)
+{
+	Model *m;
+
+	m = emalloc(sizeof *m);
+	memset(m, 0, sizeof *m);
+	return m;
+}
+
+void
+delmodel(Model *m)
+{
+	free(m);
+}
+
+Entity *
+newentity(Model *m)
+{
+	Entity *e;
+
+	e = emalloc(sizeof *e);
+	e->p = Pt3(0,0,0,1);
+	e->bx = Vec3(1,0,0);
+	e->by = Vec3(0,1,0);
+	e->bz = Vec3(0,0,1);
+	e->mdl = m;
+	e->prev = e->next = nil;
+	return e;
+}
+
+void
+delentity(Entity *e)
+{
+	/* TODO free model */
+	free(e);
+}
+
+static void
+scene_addent(Scene *s, Entity *e)
+{
+	e->prev = s->ents.prev;
+	e->next = s->ents.prev->next;
+	s->ents.prev->next = e;
+	s->ents.prev = e;
+	s->nents++;
+}
+
+Scene *
+newscene(char *name)
+{
+	Scene *s;
+
+	s = emalloc(sizeof *s);
+	s->name = name == nil? nil: strdup(name);
+	s->ents.prev = s->ents.next = &s->ents;
+	s->addent = scene_addent;
+	return s;
+}
+
+void
+delscene(Scene *s)
+{
+	/* TODO free ents */
+	free(s->name);
+	free(s);
+}