ref: d4991f0af282bbc996474af2caf59b8fd7dc35f3
dir: /model.c/
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <memdraw.h>
#include <geometry.h>
#include "graphics.h"
#include "internal.h"
Vertex
mkvert(void)
{
return (Vertex){NaI, NaI, NaI, NaI};
}
Primitive
mkprim(int type)
{
Primitive prim;
prim.type = type;
prim.v[0] = prim.v[1] = prim.v[2] = NaI;
prim.tangent = NaI;
prim.mtl = nil;
return prim;
}
Material *
newmaterial(char *name)
{
Material *mtl;
if(name == nil){
werrstr("needs a name");
return nil;
}
mtl = _emalloc(sizeof *mtl);
memset(mtl, 0, sizeof *mtl);
mtl->name = _estrdup(name);
mtl->ambient = Pt3(1,1,1,1);
mtl->diffuse = Pt3(1,1,1,1);
mtl->specular = Pt3(1,1,1,1);
return mtl;
}
void
delmaterial(Material *mtl)
{
freetexture(mtl->diffusemap);
freetexture(mtl->specularmap);
freetexture(mtl->normalmap);
free(mtl->name);
}
static usize
model_addposition(Model *m, Point3 p)
{
return itemarrayadd(m->positions, &p);
}
static usize
model_addnormal(Model *m, Point3 n)
{
return itemarrayadd(m->normals, &n);
}
static usize
model_addtexcoord(Model *m, Point2 t)
{
return itemarrayadd(m->texcoords, &t);
}
static usize
model_addcolor(Model *m, Color c)
{
return itemarrayadd(m->colors, &c);
}
static usize
model_addtangent(Model *m, Point3 T)
{
return itemarrayadd(m->tangents, &T);
}
static usize
model_addvert(Model *m, Vertex v)
{
return itemarrayadd(m->verts, &v);
}
static usize
model_addprim(Model *m, Primitive P)
{
return itemarrayadd(m->prims, &P);
}
static int
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;
}
static Material *
model_getmaterial(Model *m, char *name)
{
Material *mtl;
for(mtl = m->materials; mtl < m->materials+m->nmaterials; mtl++)
if(strcmp(mtl->name, name) == 0)
return mtl;
return nil;
}
Model *
newmodel(void)
{
Model *m;
m = _emalloc(sizeof *m);
memset(m, 0, sizeof *m);
m->positions = mkitemarray(sizeof(Point3));
m->normals = mkitemarray(sizeof(Point3));
m->texcoords = mkitemarray(sizeof(Point2));
m->colors = mkitemarray(sizeof(Color));
m->tangents = mkitemarray(sizeof(Point3));
m->verts = mkitemarray(sizeof(Vertex));
m->prims = mkitemarray(sizeof(Primitive));
m->addposition = model_addposition;
m->addnormal = model_addnormal;
m->addtexcoord = model_addtexcoord;
m->addcolor = model_addcolor;
m->addtangent = model_addtangent;
m->addvert = model_addvert;
m->addprim = model_addprim;
m->addmaterial = model_addmaterial;
m->getmaterial = model_getmaterial;
return m;
}
Model *
dupmodel(Model *m)
{
Model *nm;
Primitive *prim, *nprim;
int i;
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;
}
void
delmodel(Model *m)
{
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);
}
void
compactmodel(Model *m)
{
ItemArray *a1, *a2;
Point3 *p1, *p2, *pb, *pe;
Point2 *t1, *t2, *tb, *te;
Vertex *v, *v1, *v2, *vb, *ve;
Primitive *P, *P1, *P2, *Pb, *Pe;
void *vp;
usize len0, i, j, k;
a1 = m->positions;
pb = a1->items;
pe = pb + a1->nitems;
len0 = a1->nitems;
a2 = m->verts;
vb = a2->items;
ve = vb + a2->nitems;
for(p1 = pb, i = 0; p1 < pe; p1++, i++)
for(p2 = p1+1, j = i+1; p2 < pe; p2++, j++)
if(memcmp(p1, p2, sizeof(Point3)) == 0){
if(p2 < --pe)
memmove(p2, p2+1, (pe - p2)*sizeof(Point3));
/* reindex verts */
for(v = vb; v < ve; v++)
if(v->p == j)
v->p = i;
else if(v->p > j)
v->p--;
}
a1->nitems = pe - pb;
if(a1->nitems != len0){
vp = realloc(a1->items, a1->nitems * a1->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink positions array.\n");
else
a1->items = vp;
}
a1 = m->normals;
pb = a1->items;
pe = pb + a1->nitems;
len0 = a1->nitems;
for(p1 = pb, i = 0; p1 < pe; p1++, i++)
for(p2 = p1+1, j = i+1; p2 < pe; p2++, j++)
if(memcmp(p1, p2, sizeof(Point3)) == 0){
if(p2 < --pe)
memmove(p2, p2+1, (pe - p2)*sizeof(Point3));
/* reindex verts */
for(v = vb; v < ve; v++)
if(v->n == j)
v->n = i;
else if(v->n > j)
v->n--;
}
a1->nitems = pe - pb;
if(a1->nitems != len0){
vp = realloc(a1->items, a1->nitems * a1->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink normals array.\n");
else
a1->items = vp;
}
a1 = m->texcoords;
tb = a1->items;
te = tb + a1->nitems;
len0 = a1->nitems;
for(t1 = tb, i = 0; t1 < te; t1++, i++)
for(t2 = t1+1, j = i+1; t2 < te; t2++, j++)
if(memcmp(t1, t2, sizeof(Point2)) == 0){
if(t2 < --te)
memmove(t2, t2+1, (te - t2)*sizeof(Point2));
/* reindex verts */
for(v = vb; v < ve; v++)
if(v->uv == j)
v->uv = i;
else if(v->uv > j)
v->uv--;
}
a1->nitems = te - tb;
if(a1->nitems != len0){
vp = realloc(a1->items, a1->nitems * a1->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink texcoords array.\n");
else
a1->items = vp;
}
a1 = m->colors;
pb = a1->items;
pe = pb + a1->nitems;
len0 = a1->nitems;
for(p1 = pb, i = 0; p1 < pe; p1++, i++)
for(p2 = p1+1, j = i+1; p2 < pe; p2++, j++)
if(memcmp(p1, p2, sizeof(Point3)) == 0){
if(p2 < --pe)
memmove(p2, p2+1, (pe - p2)*sizeof(Point3));
/* reindex verts */
for(v = vb; v < ve; v++)
if(v->c == j)
v->c = i;
else if(v->c > j)
v->c--;
}
a1->nitems = pe - pb;
if(a1->nitems != len0){
vp = realloc(a1->items, a1->nitems * a1->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink colors array.\n");
else
a1->items = vp;
}
a1 = m->tangents;
pb = a1->items;
pe = pb + a1->nitems;
len0 = a1->nitems;
a2 = m->prims;
Pb = a2->items;
Pe = Pb + a2->nitems;
for(p1 = pb, i = 0; p1 < pe; p1++, i++)
for(p2 = p1+1, j = i+1; p2 < pe; p2++, j++)
if(memcmp(p1, p2, sizeof(Point3)) == 0){
if(p2 < --pe)
memmove(p2, p2+1, (pe - p2)*sizeof(Point3));
/* reindex prims */
for(P = Pb; P < Pe; P++)
if(P->tangent == j)
P->tangent = i;
else if(P->tangent > j)
P->tangent--;
}
a1->nitems = pe - pb;
if(a1->nitems != len0){
vp = realloc(a1->items, a1->nitems * a1->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink tangents array.\n");
else
a1->items = vp;
}
a1 = m->verts;
vb = a1->items;
ve = vb + a1->nitems;
len0 = a1->nitems;
for(v1 = vb, i = 0; v1 < ve; v1++, i++)
for(v2 = v1+1, j = i+1; v2 < ve; v2++, j++)
if(memcmp(v1, v2, sizeof(Vertex)) == 0){
if(v2 < --ve)
memmove(v2, v2+1, (ve - v2)*sizeof(Vertex));
/* reindex prims */
for(P = Pb; P < Pe; P++)
for(k = 0; k < P->type+1; k++)
if(P->v[k] == j)
P->v[k] = i;
else if(P->v[k] > j)
P->v[k]--;
}
a1->nitems = ve - vb;
if(a1->nitems != len0){
vp = realloc(a1->items, a1->nitems * a1->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink vertex array.\n");
else
a1->items = vp;
}
len0 = a2->nitems;
for(P1 = Pb, i = 0; P1 < Pe; P1++, i++)
for(P2 = P1+1, j = i+1; P2 < Pe; P2++, j++)
if(memcmp(P1, P2, sizeof(Primitive)) == 0)
if(P2 < --Pe)
memmove(P2, P2+1, (Pe - P2)*sizeof(Primitive));
a2->nitems = Pe - Pb;
if(a2->nitems != len0){
vp = realloc(a2->items, a2->nitems * a2->itemsize);
if(vp == nil)
fprint(2, "not enough memory to shrink vertex array.\n");
else
a2->items = vp;
}
}