shithub: libgraphics

ref: c4be6b6604962376c810fb2eace384e82b67b44c
dir: /scene.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <memdraw.h>
#include <geometry.h>
#include "libobj/obj.h"
#include "graphics.h"
#include "internal.h"

static int
model_addprim(Model *m, Primitive p)
{
	m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
	m->prims[m->nprims-1] = p;
	return 0;
}

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 0;
}

Model *
newmodel(void)
{
	Model *m;

	m = emalloc(sizeof *m);
	memset(m, 0, sizeof *m);
	m->addprim = model_addprim;
	m->addmaterial = model_addmaterial;
	return m;
}

Model *
dupmodel(Model *m)
{
	Model *nm;
	int i;

	if(m == nil)
		return nil;

	nm = newmodel();
	nm->tex = duptexture(m->tex);
	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 = strdup(m->materials[i].name);
			if(nm->materials[i].name == nil)
				sysfatal("strdup: %r");
		}
	}
	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].specularmap);
		freetexture(m->materials[m->nmaterials].normalmap);
		free(m->materials[m->nmaterials].name);
	}
	free(m->materials);
	free(m->prims);
	free(m);
}

Entity *
newentity(char *name, Model *m)
{
	Entity *e;

	e = emalloc(sizeof *e);
	e->p = Pt3(0,0,0,1);
	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;

	delmodel(e->mdl);
	free(e->name);
	free(e);
}

static void
scene_addent(Scene *s, Entity *e)
{
	e->prev = s->ents.prev;
	e->next = s->ents.prev->next;
	s->ents.prev->next = e;
	s->ents.prev = e;
	s->nents++;
}

static void
scene_delent(Scene *s, Entity *e)
{
	e->prev->next = e->next;
	e->next->prev = e->prev;
	e->prev = e->next = nil;
	s->nents--;
}

static Entity *
scene_getent(Scene *s, char *name)
{
	Entity *e;

	for(e = s->ents.next; e != &s->ents; e = e->next)
		if(strcmp(e->name, name) == 0)
			return e;
	return nil;
}

Scene *
newscene(char *name)
{
	Scene *s;

	s = emalloc(sizeof *s);
	s->name = name == nil? nil: strdup(name);
	s->ents.prev = s->ents.next = &s->ents;
	s->nents = 0;
	s->skybox = nil;
	s->addent = scene_addent;
	s->delent = scene_delent;
	s->getent = scene_getent;
	return s;
}

Scene *
dupscene(Scene *s)
{
	Scene *ns;
	Entity *e;

	if(s == nil)
		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));
	ns->skybox = dupcubemap(s->skybox);
	return ns;
}

void
clearscene(Scene *s)
{
	Entity *e, *ne;

	for(e = s->ents.next; e != &s->ents; e = ne){
		ne = e->next;
		s->delent(s, e);
		delentity(e);
	}
	freecubemap(s->skybox);
}

void
delscene(Scene *s)
{
	if(s == nil)
		return;

	clearscene(s);
	free(s->name);
	free(s);
}