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);
+}