ref: 2846ffebfc29bd997339f71f5ea6bd785e940097
parent: 5b04bd5b3a152d0b2d5a8d8e1e25887b71c338d5
author: rodri <rgl@antares-labs.eu>
date: Sun Mar 22 18:03:29 EDT 2026
turn the Model.materials into an ItemArray. rewrite dup and copy routines now ItemArray and Model are refcounted. duplicating them creates another reference, copying them creates another instance. now we can instantiate models and change specific attributes for better reuse of resources. also got rid of useless dup scenes for lights, entities and scenes.
--- a/graphics.h
+++ b/graphics.h
@@ -87,6 +87,7 @@
struct ItemArray
{+ Ref;
void *items;
usize nitems;
usize itemsize;
@@ -210,6 +211,7 @@
struct Model
{+ Ref;
char *name;
ItemArray *positions;
ItemArray *normals;
@@ -218,8 +220,7 @@
ItemArray *tangents;
ItemArray *verts;
ItemArray *prims;
- Material *materials;
- ulong nmaterials;
+ ItemArray *materials;
usize (*addposition)(Model*, Point3);
usize (*addnormal)(Model*, Point3);
@@ -228,7 +229,7 @@
usize (*addtangent)(Model*, Point3);
usize (*addvert)(Model*, Vertex);
usize (*addprim)(Model*, Primitive);
- int (*addmaterial)(Model*, Material);
+ usize (*addmaterial)(Model*, Material);
Material* (*getmaterial)(Model*, char*);
};
@@ -472,15 +473,12 @@
LightSource* newpointlight(Point3, Color);
LightSource* newdireclight(Point3, Point3, Color);
LightSource* newspotlight(Point3, Point3, Color, double, double);
-LightSource* duplight(LightSource*);
void dellight(LightSource*);
Entity* newentity(char*, Model*);
-Entity* dupentity(Entity*);
void delentity(Entity*);
Scene* newscene(char*);
-Scene* dupscene(Scene*);
-void delscene(Scene*);
void clearscene(Scene*);
+void delscene(Scene*);
/* model */
Vertex mkvert(void);
@@ -488,7 +486,8 @@
Material* newmaterial(char*);
void delmaterial(Material*);
Model* newmodel(void);
-Model* dupmodel(Model*);
+void copymodel(Model*, Model*);
+Model* dupmodel(Model*, Model**);
void delmodel(Model*);
void compactmodel(Model*);
@@ -523,7 +522,7 @@
usize itemarrayadd(ItemArray*, void*);
void* itemarrayget(ItemArray*, usize);
usize copyitemarray(ItemArray*, ItemArray*);
-ItemArray* dupitemarray(ItemArray*);
+ItemArray* dupitemarray(ItemArray*, ItemArray**);
void rmitemarray(ItemArray*);
/* color */
--- a/itemarray.c
+++ b/itemarray.c
@@ -16,6 +16,7 @@
a = _emalloc(sizeof *a);
memset(a, 0, sizeof *a);
a->itemsize = is;
+ incref(a);
return a;
}
@@ -48,33 +49,39 @@
}
usize
-copyitemarray(ItemArray *d, ItemArray *s)
+copyitemarray(ItemArray *s, ItemArray *d)
{usize len;
- assert(d->itemsize == s->itemsize);
len = s->nitems * s->itemsize;
-
free(d->items);
d->items = _emalloc(len);
d->nitems = s->nitems;
+ d->itemsize = s->itemsize;
memmove(d->items, s->items, len);
return d->nitems;
}
+/*
+ * deferring rmitemarray() makes this operation idempotent.
+ */
ItemArray *
-dupitemarray(ItemArray *a)
+dupitemarray(ItemArray *s, ItemArray **d)
{- ItemArray *na;
+ ItemArray *t;
- na = mkitemarray(a->itemsize);
- copyitemarray(na, a);
- return na;
+ t = *d;
+ *d = s;
+ incref(*d);
+ rmitemarray(t);
+ return *d;
}
void
rmitemarray(ItemArray *a)
{- free(a->items);
- free(a);
+ if(decref(a) == 0){+ free(a->items);
+ free(a);
+ }
}
--- a/marshal.c
+++ b/marshal.c
@@ -24,15 +24,14 @@
struct Mtlentry
{- Material;
- ulong idx;
- Mtlentry *next;
+ char *name;
+ ulong idx;
+ Mtlentry *next;
};
struct Mtltab
{- Mtlentry *mtls[MTLHTSIZ];
- int loaded; /* was the table loaded into a model already? */
+ Mtlentry *mtls[MTLHTSIZ];
};
static void
@@ -71,18 +70,8 @@
return t;
}
-static void
-freemtlentry(Mtlentry *m)
-{- freetexture(m->normalmap);
- freetexture(m->specularmap);
- freetexture(m->diffusemap);
- free(m->name);
- free(m);
-}
-
static Mtlentry *
-mtltabadd(Mtltab *t, Material *m)
+mtltabadd(Mtltab *t, Material *m, ulong idx)
{Mtlentry *nm, *mp, *prev;
uint h;
@@ -89,7 +78,8 @@
nm = _emalloc(sizeof *nm);
memset(nm, 0, sizeof *nm);
- nm->Material = *m;
+ nm->name = m->name;
+ nm->idx = idx;
nm->next = nil;
prev = nil;
@@ -121,18 +111,6 @@
}
static void
-mtltabloadmodel(Model *m, Mtltab *t)
-{- Mtlentry *e;
- int i;
-
- for(i = 0; i < nelem(t->mtls); i++)
- for(e = t->mtls[i]; e != nil; e = e->next)
- e->idx = m->addmaterial(m, *e);
- t->loaded++;
-}
-
-static void
rmmtltab(Mtltab *t)
{Mtlentry *m, *nm;
@@ -141,10 +119,7 @@
for(i = 0; i < nelem(t->mtls); i++)
for(m = t->mtls[i]; m != nil; m = nm){nm = m->next;
- if(t->loaded)
- free(m);
- else
- freemtlentry(m);
+ free(m);
}
}
@@ -152,7 +127,7 @@
readmodel(int fd)
{Curline curline;
- ItemArray *pa, *na, *ta, *ca, *Ta, *va, *Pa;
+ ItemArray *pa, *na, *ta, *ca, *Ta, *va, *Pa, *ma;
Mtltab *mtltab;
Mtlentry *me;
Point3 p, n, T;
@@ -159,7 +134,7 @@
Point2 t;
Color c;
Vertex v;
- Primitive P, *prim;
+ Primitive P;
Material mtl;
Model *m;
Memimage *mi;
@@ -166,7 +141,7 @@
Biobuf *bin;
void *vp;
char *line, *f[10], *s, assets[200], buf[256];
- usize idx, i;
+ usize idx;
int nf, nv, inamaterial, texfd;
n.w = T.w = 0;
@@ -184,6 +159,7 @@
Ta = mkitemarray(sizeof(T));
va = mkitemarray(sizeof(v));
Pa = mkitemarray(sizeof(P));
+ ma = mkitemarray(sizeof(mtl));
mtltab = mkmtltab();
memset(&curline, 0, sizeof curline);
@@ -212,7 +188,8 @@
*s = 0;
if(strcmp(f[0], "}") == 0){- if(mtltabadd(mtltab, &mtl) == nil){+ idx = itemarrayadd(ma, &mtl);
+ if(mtltabadd(mtltab, &mtl, idx) == nil){error(&curline, "mtltabadd: %r");
goto getout;
}
@@ -446,11 +423,12 @@
/* ignore 4th field (nf == 4) */
if(nf == 5){- P.mtl = mtltabget(mtltab, f[4]);
- if(P.mtl == nil){+ me = mtltabget(mtltab, f[4]);
+ if(me == nil){error(&curline, "material '%s' not found", f[4]);
goto getout;
}
+ P.mtl = itemarrayget(ma, me->idx);
}
break;
case PLine:
@@ -476,11 +454,12 @@
/* ignore 5th field (nf == 5) */
if(nf == 6){- P.mtl = mtltabget(mtltab, f[5]);
- if(P.mtl == nil){+ me = mtltabget(mtltab, f[5]);
+ if(me == nil){error(&curline, "material '%s' not found", f[5]);
goto getout;
}
+ P.mtl = itemarrayget(ma, me->idx);
}
break;
case PTriangle:
@@ -523,11 +502,12 @@
}
if(nf == 7){- P.mtl = mtltabget(mtltab, f[6]);
- if(P.mtl == nil){+ me = mtltabget(mtltab, f[6]);
+ if(me == nil){error(&curline, "material '%s' not found", f[6]);
goto getout;
}
+ P.mtl = itemarrayget(ma, me->idx);
}
break;
default:
@@ -557,21 +537,14 @@
}
m = newmodel();
- mtltabloadmodel(m, mtltab);
- copyitemarray(m->positions, pa);
- copyitemarray(m->normals, na);
- copyitemarray(m->texcoords, ta);
- copyitemarray(m->colors, ca);
- copyitemarray(m->tangents, Ta);
- copyitemarray(m->verts, va);
- copyitemarray(m->prims, Pa);
- for(i = 0; i < Pa->nitems; i++){- prim = itemarrayget(m->prims, i);
- if(prim->mtl != nil){- me = mtltabget(mtltab, prim->mtl->name);
- prim->mtl = &m->materials[me->idx];
- }
- }
+ dupitemarray(pa, &m->positions);
+ dupitemarray(na, &m->normals);
+ dupitemarray(ta, &m->texcoords);
+ dupitemarray(ca, &m->colors);
+ dupitemarray(Ta, &m->tangents);
+ dupitemarray(va, &m->verts);
+ dupitemarray(Pa, &m->prims);
+ dupitemarray(ma, &m->materials);
getout:
rmitemarray(pa);
@@ -581,6 +554,7 @@
rmitemarray(Ta);
rmitemarray(va);
rmitemarray(Pa);
+ rmitemarray(ma);
rmmtltab(mtltab);
Bterm(bin);
return m;
@@ -769,8 +743,8 @@
sysfatal("Bfdopen: %r");n = 0;
- for(i = 0; i < m->nmaterials; i++)
- n += Bprintmtl(out, &m->materials[i]);
+ for(i = 0; i < m->materials->nitems; i++)
+ n += Bprintmtl(out, itemarrayget(m->materials, i));
for(i = 0; i < m->positions->nitems; i++)
n += Bprintp(out, itemarrayget(m->positions, i));
@@ -814,16 +788,15 @@
exportmodel(char *path, Model *m)
{static char Esmallbuf[] = "buf too small to hold path";
- Material *mtl;
+ Material *mtl, *lastmtl;
char buf[256], *pe, *me;
int fd, idx;
- idx = 0;
-
if((pe = seprint(buf, buf + sizeof buf, "%s", path)) == nil)
sysfatal(Esmallbuf);
- for(mtl = m->materials; mtl < m->materials+m->nmaterials; mtl++, idx++){+ mtl = m->materials->items;
+ for(idx = 0, lastmtl = mtl + m->materials->nitems; mtl < lastmtl; mtl++, idx++){ if(mtl->name == nil){fprint(2, "warning: material #%d has no name. skipping...\n", idx);
continue;
@@ -881,7 +854,8 @@
}
close(fd);
- for(mtl = m->materials; mtl < m->materials+m->nmaterials; mtl++){+ mtl = m->materials->items;
+ for(lastmtl = mtl + m->materials->nitems; mtl < lastmtl; mtl++){if(mtl->name == nil)
continue;
--- a/model.c
+++ b/model.c
@@ -30,7 +30,7 @@
{Material *mtl;
- if(name == nil){+ if(name == nil || name[0] == '\0'){ werrstr("needs a name");return nil;
}
@@ -51,6 +51,7 @@
freetexture(mtl->specularmap);
freetexture(mtl->normalmap);
free(mtl->name);
+ free(mtl);
}
static usize
@@ -95,20 +96,23 @@
return itemarrayadd(m->prims, &P);
}
-static int
+static usize
model_addmaterial(Model *m, Material mtl)
{- m->materials = _erealloc(m->materials, ++m->nmaterials*sizeof(*m->materials));
- m->materials[m->nmaterials-1] = mtl;
- return m->nmaterials-1;
+ assert(mtl.name != nil);
+ return itemarrayadd(m->materials, &mtl);
}
static Material *
model_getmaterial(Model *m, char *name)
{- Material *mtl;
+ Material *mtl, *last;
- for(mtl = m->materials; mtl < m->materials+m->nmaterials; mtl++)
+ if(name == nil)
+ return nil;
+
+ mtl = m->materials->items;
+ for(last = mtl + m->materials->nitems; mtl < last; mtl++)
if(strcmp(mtl->name, name) == 0)
return mtl;
return nil;
@@ -128,6 +132,7 @@
m->tangents = mkitemarray(sizeof(Point3));
m->verts = mkitemarray(sizeof(Vertex));
m->prims = mkitemarray(sizeof(Primitive));
+ m->materials = mkitemarray(sizeof(Material));
m->addposition = model_addposition;
m->addnormal = model_addnormal;
m->addtexcoord = model_addtexcoord;
@@ -137,46 +142,36 @@
m->addprim = model_addprim;
m->addmaterial = model_addmaterial;
m->getmaterial = model_getmaterial;
+ incref(m);
return m;
}
+void
+copymodel(Model *s, Model *d)
+{+ if(d->name)
+ free(d->name);
+ d->name = s->name? _estrdup(s->name): nil;
+ dupitemarray(s->positions, &d->positions);
+ dupitemarray(s->normals, &d->normals);
+ dupitemarray(s->texcoords, &d->texcoords);
+ dupitemarray(s->colors, &d->colors);
+ dupitemarray(s->tangents, &d->tangents);
+ dupitemarray(s->verts, &d->verts);
+ dupitemarray(s->prims, &d->prims);
+ dupitemarray(s->materials, &d->materials);
+}
+
Model *
-dupmodel(Model *m)
+dupmodel(Model *s, Model **d)
{- Model *nm;
- Primitive *prim, *nprim;
- int i;
+ Model *t;
- if(m == nil)
- return nil;
-
- nm = newmodel();
- if(m->nmaterials > 0){- 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].specularmap = duptexture(m->materials[i].specularmap);
- nm->materials[i].normalmap = duptexture(m->materials[i].normalmap);
- nm->materials[i].name = _estrdup(m->materials[i].name);
- }
- }
- nm->positions = dupitemarray(m->positions);
- nm->normals = dupitemarray(m->normals);
- nm->texcoords = dupitemarray(m->texcoords);
- nm->colors = dupitemarray(m->colors);
- nm->tangents = dupitemarray(m->tangents);
- nm->verts = dupitemarray(m->verts);
- nm->prims = dupitemarray(m->prims);
- for(i = 0; i < m->prims->nitems && nm->nmaterials > 0; i++){- prim = itemarrayget(m->prims, i);
- if(prim->mtl != nil){- nprim = itemarrayget(nm->prims, i);
- nprim->mtl = &nm->materials[prim->mtl - m->materials];
- }
- }
- return nm;
+ t = *d;
+ *d = s;
+ incref(*d);
+ delmodel(t);
+ return *d;
}
void
@@ -185,17 +180,18 @@
if(m == nil)
return;
- while(m->nmaterials--)
- delmaterial(&m->materials[m->nmaterials]);
- free(m->materials);
- rmitemarray(m->positions);
- rmitemarray(m->normals);
- rmitemarray(m->texcoords);
- rmitemarray(m->colors);
- rmitemarray(m->tangents);
- rmitemarray(m->verts);
- rmitemarray(m->prims);
- free(m);
+ if(decref(m) == 0){+ rmitemarray(m->positions);
+ rmitemarray(m->normals);
+ rmitemarray(m->texcoords);
+ rmitemarray(m->colors);
+ rmitemarray(m->tangents);
+ rmitemarray(m->verts);
+ rmitemarray(m->prims);
+ rmitemarray(m->materials);
+ free(m->name);
+ free(m);
+ }
}
/*
--- a/scene.c
+++ b/scene.c
@@ -42,18 +42,6 @@
return newlight(LightSpot, p, dir, c, 1000, θu, θp);
}
-LightSource *
-duplight(LightSource *l)
-{- LightSource *nl;
-
- nl = _emalloc(sizeof *nl);
- memset(nl, 0, sizeof *nl);
- *nl = *l;
- nl->prev = nl->next = nil;
- return nl;
-}
-
void
dellight(LightSource *l)
{@@ -76,23 +64,6 @@
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 = _estrdup(e->name);
- ne->mdl = dupmodel(e->mdl);
- ne->prev = ne->next = nil;
- return ne;
-}
-
void
delentity(Entity *e)
{@@ -161,25 +132,6 @@
s->getent = scene_getent;
s->addlight = scene_addlight;
return s;
-}
-
-Scene *
-dupscene(Scene *s)
-{- Scene *ns;
- Entity *e;
- LightSource *l;
-
- if(s == nil)
- return nil;
-
- ns = newscene(s->name);
- for(e = s->ents.next; e != &s->ents; e = e->next)
- ns->addent(ns, dupentity(e));
- for(l = s->lights.next; l != &s->lights; l = l->next)
- ns->addlight(ns, duplight(l));
- ns->skybox = dupcubemap(s->skybox);
- return ns;
}
void
--
⑨