From 5b93335dd430e09a71ebaba131826cd7db154cb4 Mon Sep 17 00:00:00 2001 From: rodri Date: Tue, 13 Feb 2024 16:40:31 +0000 Subject: 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. --- camera.c | 5 +- graphics.h | 32 ++++++++--- internal.h | 2 +- mkfile | 1 + render.c | 146 +++++++----------------------------------------- scene.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 234 insertions(+), 137 deletions(-) create mode 100644 scene.c diff --git a/camera.c b/camera.c index b52b6b4..82d0b0b 100644 --- a/camera.c +++ b/camera.c @@ -78,14 +78,13 @@ reloadcamera(Camera *c) } 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); diff --git a/graphics.h b/graphics.h index 433d7b8..d517b33 100644 --- a/graphics.h +++ b/graphics.h @@ -16,7 +16,7 @@ typedef struct LightSource LightSource; 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 Material 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 FSparams 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 @@ struct Camera { RFrame3; /* VCS */ Viewport *vp; + Scene *s; double fov; /* vertical FOV */ struct { double n, f; /* near and far clipping planes */ @@ -162,7 +171,7 @@ void configcamera(Camera*, Viewport*, double, double, double, Projection); 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); @@ -175,6 +184,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); double fmax(double, double); diff --git a/internal.h b/internal.h index 6abb115..0c66625 100644 --- a/internal.h +++ b/internal.h @@ -10,7 +10,7 @@ Framebufctl *mkfbctl(Rectangle); void rmfbctl(Framebufctl*); /* render */ -void shade(Framebuf*, OBJ*, Memimage*, Shader*, ulong); +void shade(Framebuf*, Scene*, Shader*); /* util */ int min(int, int); diff --git a/mkfile b/mkfile index 9190fe8..5956ba1 100644 --- a/mkfile +++ b/mkfile @@ -5,6 +5,7 @@ OFILES=\ camera.$O\ viewport.$O\ render.$O\ + scene.$O\ alloc.$O\ fb.$O\ shadeop.$O\ diff --git a/render.c b/render.c index e5bfa51..05a1de1 100644 --- a/render.c +++ b/render.c @@ -20,74 +20,6 @@ pixel(Memimage *dst, Point p, Memimage *src) 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) { @@ -157,9 +89,6 @@ cliptriangle(Triangle *t) 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 @@ rasterize(SUparams *params, Triangle t, Memimage *frag) 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 @@ shaderunit(void *arg) 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 @@ shaderunit(void *arg) 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 @@ shaderunit(void *arg) } 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 @@ shaderunit(void *arg) } 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--) diff --git a/scene.c b/scene.c new file mode 100644 index 0000000..b7aab97 --- /dev/null +++ b/scene.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#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); +} -- cgit v1.2.3