summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--camera.c67
-rw-r--r--clip.c21
-rw-r--r--graphics.h10
-rw-r--r--internal.h2
-rw-r--r--render.c146
-rw-r--r--scene.c125
-rw-r--r--texture.c19
-rw-r--r--util.c15
8 files changed, 260 insertions, 145 deletions
diff --git a/camera.c b/camera.c
index 60f3c4a..ed220a3 100644
--- a/camera.c
+++ b/camera.c
@@ -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);
}
diff --git a/clip.c b/clip.c
index db1f58e..a7750cf 100644
--- a/clip.c
+++ b/clip.c
@@ -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;
}
diff --git a/graphics.h b/graphics.h
index fbeea2f..47a41cd 100644
--- a/graphics.h
+++ b/graphics.h
@@ -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);
diff --git a/internal.h b/internal.h
index 6e66229..361b013 100644
--- a/internal.h
+++ b/internal.h
@@ -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 */
diff --git a/render.c b/render.c
index 278c186..3d980af 100644
--- a/render.c
+++ b/render.c
@@ -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");
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);
}
diff --git a/texture.c b/texture.c
index 86b2cbd..c75f29c 100644
--- a/texture.c
+++ b/texture.c
@@ -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);
diff --git a/util.c b/util.c
index db538a3..0b9003e 100644
--- a/util.c
+++ b/util.c
@@ -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;
+}