diff options
-rw-r--r-- | camera.c | 67 | ||||
-rw-r--r-- | clip.c | 21 | ||||
-rw-r--r-- | graphics.h | 10 | ||||
-rw-r--r-- | internal.h | 2 | ||||
-rw-r--r-- | render.c | 146 | ||||
-rw-r--r-- | scene.c | 125 | ||||
-rw-r--r-- | texture.c | 19 | ||||
-rw-r--r-- | util.c | 15 |
8 files changed, 260 insertions, 145 deletions
@@ -106,6 +106,36 @@ verifycfg(Camera *c) assert(c->clip.n > 0 && c->clip.n < c->clip.f); } +/* TODO the current camera abstraction is quite dirty, not pleasant to work with. make it better. */ +//Camera * +//Cam(Camcfg cfg) +//{ +// +//} + +void +reloadcamera(Camera *c) +{ + double a; + double l, r, b, t; + + verifycfg(c); + switch(c->projtype){ + case ORTHOGRAPHIC: + r = Dx(c->vp->fbctl->fb[0]->r)/2; + t = Dy(c->vp->fbctl->fb[0]->r)/2; + l = -r; + b = -t; + orthographic(c->proj, l, r, b, t, c->clip.n, c->clip.f); + break; + case PERSPECTIVE: + a = (double)Dx(c->vp->fbctl->fb[0]->r)/Dy(c->vp->fbctl->fb[0]->r); + perspective(c->proj, c->fov, a, c->clip.n, c->clip.f); + break; + default: sysfatal("unknown projection type"); + } +} + void configcamera(Camera *c, Viewport *v, double fov, double n, double f, Projection p) { @@ -133,29 +163,6 @@ aimcamera(Camera *c, Point3 focus) } void -reloadcamera(Camera *c) -{ - double a; - double l, r, b, t; - - verifycfg(c); - switch(c->projtype){ - case ORTHOGRAPHIC: - r = Dx(c->vp->fbctl->fb[0]->r)/2; - t = Dy(c->vp->fbctl->fb[0]->r)/2; - l = -r; - b = -t; - orthographic(c->proj, l, r, b, t, c->clip.n, c->clip.f); - break; - case PERSPECTIVE: - a = (double)Dx(c->vp->fbctl->fb[0]->r)/Dy(c->vp->fbctl->fb[0]->r); - perspective(c->proj, c->fov, a, c->clip.n, c->clip.f); - break; - default: sysfatal("unknown projection type"); - } -} - -void shootcamera(Camera *c, Shadertab *s) { static Scene *skyboxscene; @@ -167,8 +174,9 @@ shootcamera(Camera *c, Shadertab *s) job = emalloc(sizeof *job); memset(job, 0, sizeof *job); job->fb = c->vp->fbctl->getbb(c->vp->fbctl); - job->camera = c; - job->scene = c->scene; + job->camera = emalloc(sizeof *c); + *job->camera = *c; + job->scene = dupscene(c->scene); /* take a snapshot */ job->shaders = s; job->donec = chancreate(sizeof(void*), 0); @@ -176,21 +184,23 @@ shootcamera(Camera *c, Shadertab *s) t0 = nanosec(); sendp(c->rctl->c, job); recvp(job->donec); + delscene(job->scene); /* destroy the snapshot */ /* * if the scene has a skybox, do another render pass, - * filling in the fragments left untouched by the z-buffer. + * filling in the pixels left untouched. */ if(c->scene->skybox != nil){ if(skyboxscene == nil){ skyboxscene = newscene("skybox"); mdl = mkskyboxmodel(); - skyboxscene->addent(skyboxscene, newentity(mdl)); + skyboxscene->addent(skyboxscene, newentity("skybox", mdl)); } skyboxscene->skybox = c->scene->skybox; - job->scene = skyboxscene; + job->scene = dupscene(skyboxscene); job->shaders = &skyboxshader; sendp(c->rctl->c, job); recvp(job->donec); + delscene(job->scene); } t1 = nanosec(); c->vp->fbctl->swap(c->vp->fbctl); @@ -199,5 +209,6 @@ shootcamera(Camera *c, Shadertab *s) updatetimes(c, job); chanfree(job->donec); + free(job->camera); free(job); } @@ -75,7 +75,7 @@ eqpt3(Point3 a, Point3 b) * - https://github.com/aap/librw/blob/14dab85dcae6f3762fb2b1eda4d58d8e67541330/tools/playground/tl_tests.cpp#L522 */ int -clipprimitive(Primitive *p) +clipprimitive(Primitive *p, Primitive *cp) { /* signed distance from each clipping plane */ static double sdm[6][4] = { @@ -97,8 +97,8 @@ clipprimitive(Primitive *p) Vout = &Voutp; memset(Vin, 0, sizeof Vinp); memset(Vout, 0, sizeof Voutp); - for(i = 0; i < p[0].type+1; i++) - addvert(Vin, p[0].v[i]); + for(i = 0; i < p->type+1; i++) + addvert(Vin, p->v[i]); for(j = 0; j < 6 && Vin->n > 0; j++){ for(i = 0; i < Vin->n; i++){ @@ -133,10 +133,11 @@ allin: if(Vout->n < 2) cleanpoly(Vout); - else switch(p[0].type){ + else switch(p->type){ case PLine: - p[0].v[0] = dupvertex(&Vout->v[0]); - p[0].v[1] = eqpt3(Vout->v[0].p, Vout->v[1].p)? dupvertex(&Vout->v[2]): dupvertex(&Vout->v[1]); + cp[0] = *p; + cp[0].v[0] = dupvertex(&Vout->v[0]); + cp[0].v[1] = eqpt3(Vout->v[0].p, Vout->v[1].p)? dupvertex(&Vout->v[2]): dupvertex(&Vout->v[1]); cleanpoly(Vout); np = 1; break; @@ -148,10 +149,10 @@ allin: * are referenced on every triangle, so duplicate them * to avoid complications during rasterization. */ - p[np] = p[0]; - p[np].v[0] = i < Vout->n-2-1? dupvertex(&Vout->v[0]): Vout->v[0]; - p[np].v[1] = Vout->v[i+1]; - p[np].v[2] = i < Vout->n-2-1? dupvertex(&Vout->v[i+2]): Vout->v[i+2]; + cp[np] = *p; + cp[np].v[0] = i < Vout->n-2-1? dupvertex(&Vout->v[0]): Vout->v[0]; + cp[np].v[1] = Vout->v[i+1]; + cp[np].v[2] = i < Vout->n-2-1? dupvertex(&Vout->v[i+2]): Vout->v[i+2]; } break; } @@ -156,6 +156,7 @@ struct Model struct Entity { RFrame3; + char *name; Model *mdl; Entity *prev, *next; @@ -294,10 +295,10 @@ struct Camera }; /* camera */ +void reloadcamera(Camera*); void configcamera(Camera*, Viewport*, double, double, double, Projection); void placecamera(Camera*, Point3, Point3, Point3); void aimcamera(Camera*, Point3); -void reloadcamera(Camera*); void shootcamera(Camera*, Shadertab*); /* viewport */ @@ -326,10 +327,13 @@ void orthographic(Matrix3, double, double, double, double, double, double); /* scene */ int loadobjmodel(Model*, OBJ*); Model *newmodel(void); +Model *dupmodel(Model*); void delmodel(Model*); -Entity *newentity(Model*); +Entity *newentity(char*, Model*); +Entity *dupentity(Entity*); void delentity(Entity*); Scene *newscene(char*); +Scene *dupscene(Scene*); void delscene(Scene*); void clearscene(Scene*); @@ -339,6 +343,7 @@ Vertexattr *getvattr(Vertex*, char*); /* texture */ Texture *alloctexture(int, Memimage*); +Texture *duptexture(Texture*); void freetexture(Texture*); Color neartexsampler(Texture*, Point2); Color bilitexsampler(Texture*, Point2); @@ -353,6 +358,7 @@ double fmax(double, double); Point2 modulapt2(Point2, Point2); Point3 modulapt3(Point3, Point3); Memimage *rgb(ulong); +Memimage *dupmemimage(Memimage*); /* color */ Color srgb2linear(Color); @@ -51,7 +51,7 @@ void delvattrs(Vertex*); void fprintvattrs(int, Vertex*); /* clip */ -int clipprimitive(Primitive*); +int clipprimitive(Primitive*, Primitive*); int rectclipline(Rectangle, Point*, Point*); /* util */ @@ -67,13 +67,13 @@ isvisible(Point3 p) } static int -isfacingback(Primitive p) +isfacingback(Primitive *p) { double sa; /* signed area */ - 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; + 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; } @@ -277,7 +277,7 @@ tilerdurden(void *arg) SUparams *params, *newparams; Rastertask *task; VSparams vsp; - Primitive *ep, *p; /* primitives to raster */ + Primitive *ep, *cp, *p; /* primitives to raster */ Rectangle *wr, bbox; Channel **taskchans; ulong Δy, nproc; @@ -285,7 +285,7 @@ tilerdurden(void *arg) uvlong t0; tp = arg; - p = emalloc(sizeof(*p)*16); + cp = emalloc(sizeof(*cp)*16); taskchans = tp->taskchans; nproc = tp->nproc; wr = emalloc(nproc*sizeof(Rectangle)); @@ -323,27 +323,27 @@ tilerdurden(void *arg) for(ep = params->eb; ep != params->ee; ep++){ np = 1; /* start with one. after clipping it might change */ - *p = *ep; - switch(ep->type){ + p = ep; + switch(p->type){ case PPoint: - p[0].v[0].mtl = ep->mtl; - p[0].v[0].attrs = nil; - p[0].v[0].nattrs = 0; + p->v[0].mtl = p->mtl; + p->v[0].attrs = nil; + p->v[0].nattrs = 0; - vsp.v = &p[0].v[0]; + vsp.v = &p->v[0]; vsp.idx = 0; - p[0].v[0].p = params->vshader(&vsp); + p->v[0].p = params->vshader(&vsp); - if(!isvisible(p[0].v[0].p)) + if(!isvisible(p->v[0].p)) break; - p[0].v[0].p = clip2ndc(p[0].v[0].p); - p[0].v[0].p = ndc2viewport(params->fb, p[0].v[0].p); + p->v[0].p = clip2ndc(p->v[0].p); + p->v[0].p = ndc2viewport(params->fb, p->v[0].p); - bbox.min.x = p[0].v[0].p.x; - bbox.min.y = p[0].v[0].p.y; - bbox.max.x = p[0].v[0].p.x+1; - bbox.max.y = p[0].v[0].p.y+1; + bbox.min.x = p->v[0].p.x; + bbox.min.y = p->v[0].p.y; + bbox.max.x = p->v[0].p.x+1; + bbox.max.y = p->v[0].p.y+1; for(i = 0; i < nproc; i++) if(rectXrect(bbox,wr[i])){ @@ -352,37 +352,39 @@ tilerdurden(void *arg) task = emalloc(sizeof *task); task->params = newparams; task->wr = wr[i]; - task->p = p[0]; - task->p.v[0] = dupvertex(&p[0].v[0]); + task->p = *p; + task->p.v[0] = dupvertex(&p->v[0]); sendp(taskchans[i], task); } - delvattrs(&p[0].v[0]); + delvattrs(&p->v[0]); break; case PLine: for(i = 0; i < 2; i++){ - p[0].v[i].mtl = ep->mtl; - p[0].v[i].attrs = nil; - p[0].v[i].nattrs = 0; + p->v[i].mtl = p->mtl; + p->v[i].attrs = nil; + p->v[i].nattrs = 0; - vsp.v = &p[0].v[i]; + vsp.v = &p->v[i]; vsp.idx = i; - p[0].v[i].p = params->vshader(&vsp); + p->v[i].p = params->vshader(&vsp); } - if(!isvisible(p[0].v[0].p) || !isvisible(p[0].v[1].p)) - np = clipprimitive(p); + if(!isvisible(p->v[0].p) || !isvisible(p->v[1].p)){ + np = clipprimitive(p, cp); + p = cp; + } - while(np--){ - p[np].v[0].p = clip2ndc(p[np].v[0].p); - p[np].v[1].p = clip2ndc(p[np].v[1].p); + for(; np--; p++){ + p->v[0].p = clip2ndc(p->v[0].p); + p->v[1].p = clip2ndc(p->v[1].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->v[0].p = ndc2viewport(params->fb, p->v[0].p); + p->v[1].p = ndc2viewport(params->fb, p->v[1].p); - bbox.min.x = min(p[np].v[0].p.x, p[np].v[1].p.x); - bbox.min.y = min(p[np].v[0].p.y, p[np].v[1].p.y); - bbox.max.x = max(p[np].v[0].p.x, p[np].v[1].p.x)+1; - bbox.max.y = max(p[np].v[0].p.y, p[np].v[1].p.y)+1; + bbox.min.x = min(p->v[0].p.x, p->v[1].p.x); + bbox.min.y = min(p->v[0].p.y, p->v[1].p.y); + bbox.max.x = max(p->v[0].p.x, p->v[1].p.x)+1; + bbox.max.y = max(p->v[0].p.y, p->v[1].p.y)+1; for(i = 0; i < nproc; i++) if(rectXrect(bbox,wr[i])){ @@ -391,47 +393,49 @@ tilerdurden(void *arg) task = emalloc(sizeof *task); task->params = newparams; task->wr = wr[i]; - task->p = p[np]; - task->p.v[0] = dupvertex(&p[np].v[0]); - task->p.v[1] = dupvertex(&p[np].v[1]); + task->p = *p; + task->p.v[0] = dupvertex(&p->v[0]); + task->p.v[1] = dupvertex(&p->v[1]); sendp(taskchans[i], task); } - delvattrs(&p[np].v[0]); - delvattrs(&p[np].v[1]); + delvattrs(&p->v[0]); + delvattrs(&p->v[1]); } break; case PTriangle: for(i = 0; i < 3; i++){ - p[0].v[i].mtl = p->mtl; - p[0].v[i].attrs = nil; - p[0].v[i].nattrs = 0; - p[0].v[i].tangent = p->tangent; + p->v[i].mtl = p->mtl; + p->v[i].attrs = nil; + p->v[i].nattrs = 0; + p->v[i].tangent = p->tangent; - vsp.v = &p[0].v[i]; + vsp.v = &p->v[i]; vsp.idx = i; - p[0].v[i].p = params->vshader(&vsp); + p->v[i].p = params->vshader(&vsp); } - if(!isvisible(p[0].v[0].p) || !isvisible(p[0].v[1].p) || !isvisible(p[0].v[2].p)) - np = clipprimitive(p); + if(!isvisible(p->v[0].p) || !isvisible(p->v[1].p) || !isvisible(p->v[2].p)){ + np = clipprimitive(p, cp); + p = cp; + } - 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); + for(; np--; p++){ + p->v[0].p = clip2ndc(p->v[0].p); + p->v[1].p = clip2ndc(p->v[1].p); + p->v[2].p = clip2ndc(p->v[2].p); /* culling */ -// if(isfacingback(p[np])) +// if(isfacingback(*p)) // goto skiptri; - 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); + p->v[0].p = ndc2viewport(params->fb, p->v[0].p); + p->v[1].p = ndc2viewport(params->fb, p->v[1].p); + p->v[2].p = ndc2viewport(params->fb, p->v[2].p); - bbox.min.x = min(min(p[np].v[0].p.x, p[np].v[1].p.x), p[np].v[2].p.x); - bbox.min.y = min(min(p[np].v[0].p.y, p[np].v[1].p.y), p[np].v[2].p.y); - bbox.max.x = max(max(p[np].v[0].p.x, p[np].v[1].p.x), p[np].v[2].p.x)+1; - bbox.max.y = max(max(p[np].v[0].p.y, p[np].v[1].p.y), p[np].v[2].p.y)+1; + bbox.min.x = min(min(p->v[0].p.x, p->v[1].p.x), p->v[2].p.x); + bbox.min.y = min(min(p->v[0].p.y, p->v[1].p.y), p->v[2].p.y); + bbox.max.x = max(max(p->v[0].p.x, p->v[1].p.x), p->v[2].p.x)+1; + bbox.max.y = max(max(p->v[0].p.y, p->v[1].p.y), p->v[2].p.y)+1; for(i = 0; i < nproc; i++) if(rectXrect(bbox,wr[i])){ @@ -440,16 +444,16 @@ tilerdurden(void *arg) task = emalloc(sizeof *task); task->params = newparams; task->wr = wr[i]; - task->p = p[np]; - 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]); + task->p = *p; + task->p.v[0] = dupvertex(&p->v[0]); + task->p.v[1] = dupvertex(&p->v[1]); + task->p.v[2] = dupvertex(&p->v[2]); sendp(taskchans[i], task); } //skiptri: - delvattrs(&p[np].v[0]); - delvattrs(&p[np].v[1]); - delvattrs(&p[np].v[2]); + delvattrs(&p->v[0]); + delvattrs(&p->v[1]); + delvattrs(&p->v[2]); } break; default: sysfatal("alien primitive detected"); @@ -166,18 +166,12 @@ loadobjmodel(Model *m, OBJ *obj) if(objmtl->map_Kd != nil){ mtl->diffusemap = alloctexture(sRGBTexture, nil); - mtl->diffusemap->image = allocmemimaged(objmtl->map_Kd->r, objmtl->map_Kd->chan, objmtl->map_Kd->data); - if(mtl->diffusemap->image == nil) - sysfatal("allocmemimaged: %r"); - mtl->diffusemap->image->data->ref++; + mtl->diffusemap->image = dupmemimage(objmtl->map_Kd); } if(objmtl->norm != nil){ mtl->normalmap = alloctexture(RAWTexture, nil); - mtl->normalmap->image = allocmemimaged(objmtl->norm->r, objmtl->norm->chan, objmtl->norm->data); - if(mtl->normalmap->image == nil) - sysfatal("allocmemimaged: %r"); - mtl->normalmap->image->data->ref++; + mtl->normalmap->image = dupmemimage(objmtl->norm); } addmtlmap(&mtlmap, objmtl, m->nmaterials-1); @@ -318,29 +312,61 @@ newmodel(void) return m; } -void -delmodel(Model *m) +Model * +dupmodel(Model *m) { + Model *nm; + int i; + if(m == nil) - return; + return nil; + + nm = newmodel(); if(m->tex != nil) - freetexture(m->tex); + nm->tex = duptexture(m->tex); if(m->nmaterials > 0){ - while(m->nmaterials--){ - freetexture(m->materials[m->nmaterials].diffusemap); - freetexture(m->materials[m->nmaterials].normalmap); - free(m->materials[m->nmaterials].name); + nm->nmaterials = m->nmaterials; + nm->materials = emalloc(nm->nmaterials*sizeof(*nm->materials)); + for(i = 0; i < m->nmaterials; i++){ + nm->materials[i] = m->materials[i]; + nm->materials[i].diffusemap = duptexture(m->materials[i].diffusemap); + nm->materials[i].normalmap = duptexture(m->materials[i].normalmap); + nm->materials[i].name = strdup(m->materials[i].name); + if(nm->materials[i].name == nil) + sysfatal("strdup: %r"); } - free(m->materials); } - if(m->nprims > 0) - free(m->prims); - memset(m, 0, sizeof *m); + if(m->nprims > 0){ + nm->nprims = m->nprims; + nm->prims = emalloc(nm->nprims*sizeof(*nm->prims)); + for(i = 0; i < m->nprims; i++){ + nm->prims[i] = m->prims[i]; + if(nm->nmaterials > 0 && m->prims[i].mtl != nil) + nm->prims[i].mtl = &nm->materials[m->prims[i].mtl - m->materials]; + } + } + return nm; +} + +void +delmodel(Model *m) +{ + if(m == nil) + return; + + freetexture(m->tex); + while(m->nmaterials--){ + freetexture(m->materials[m->nmaterials].diffusemap); + freetexture(m->materials[m->nmaterials].normalmap); + free(m->materials[m->nmaterials].name); + } + free(m->materials); + free(m->prims); free(m); } Entity * -newentity(Model *m) +newentity(char *name, Model *m) { Entity *e; @@ -349,19 +375,37 @@ newentity(Model *m) e->bx = Vec3(1,0,0); e->by = Vec3(0,1,0); e->bz = Vec3(0,0,1); + e->name = name == nil? nil: strdup(name); e->mdl = m; e->prev = e->next = nil; return e; } +Entity * +dupentity(Entity *e) +{ + Entity *ne; + + if(e == nil) + return nil; + + ne = newentity(nil, nil); + *ne = *e; + if(e->name != nil) + ne->name = strdup(e->name); + ne->mdl = dupmodel(e->mdl); + ne->prev = ne->next = nil; + return ne; +} + void delentity(Entity *e) { if(e == nil) return; - if(e->mdl != nil) - delmodel(e->mdl); - memset(e, 0, sizeof *e); + + delmodel(e->mdl); + free(e->name); free(e); } @@ -399,15 +443,20 @@ newscene(char *name) return s; } -void -delscene(Scene *s) +Scene * +dupscene(Scene *s) { + Scene *ns; + Entity *e; + if(s == nil) - return; - clearscene(s); - free(s->name); - memset(s, 0, sizeof *s); - free(s); + return nil; + + ns = newscene(s->name); + if(s->nents > 0) + for(e = s->ents.next; e != &s->ents; e = e->next) + ns->addent(ns, dupentity(e)); + return ns; } void @@ -420,6 +469,16 @@ clearscene(Scene *s) s->delent(s, e); delentity(e); } - if(s->skybox != nil) - freecubemap(s->skybox); + freecubemap(s->skybox); +} + +void +delscene(Scene *s) +{ + if(s == nil) + return; + + clearscene(s); + free(s->name); + free(s); } @@ -122,9 +122,25 @@ alloctexture(int type, Memimage *i) return t; } +Texture * +duptexture(Texture *t) +{ + Texture *nt; + + if(t == nil) + return nil; + + nt = alloctexture(t->type, nil); + nt->image = dupmemimage(t->image); + return nt; +} + void freetexture(Texture *t) { + if(t == nil) + return; + freememimage(t->image); free(t); } @@ -161,6 +177,9 @@ freecubemap(Cubemap *cm) { int i; + if(cm == nil) + return; + for(i = 0; i < 6; i++) freetexture(cm->faces[i]); free(cm->name); @@ -84,3 +84,18 @@ rgb(ulong c) memfillcolor(i, c); return i; } + +Memimage * +dupmemimage(Memimage *i) +{ + Memimage *ni; + + if(i == nil) + return nil; + + ni = allocmemimaged(i->r, i->chan, i->data); + if(ni == nil) + sysfatal("allocmemimaged: %r"); + ni->data->ref++; + return ni; +} |