From 04d50b8bbe324fdb7a8a1e724fbc59c4050862f0 Mon Sep 17 00:00:00 2001 From: rodri Date: Sat, 13 Jul 2024 10:23:52 +0000 Subject: fix the geometry glitches when moving things around. it's possible for interactive programs to keep updating the geometry of the scene during rendering, which caused primitives to look deformed or shattered in the final image. to avoid this we take a snapshot of the current state of things (scene and camera), and render based on that copy. --- scene.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 33 deletions(-) (limited to 'scene.c') diff --git a/scene.c b/scene.c index ba30de9..95c6203 100644 --- a/scene.c +++ b/scene.c @@ -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); } -- cgit v1.2.3