shithub: libgraphics

ref: 96eb8b3c74e8d95579dbd8a3727b7c25f4d49ba2
dir: /vertex.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 void
_addvattr(Vertex *v, Vertexattr *va)
{
	int i;

	for(i = 0; i < v->nattrs; i++)
		if(strcmp(v->attrs[i].id, va->id) == 0){
			v->attrs[i] = *va;
			return;
		}
	v->attrs = erealloc(v->attrs, ++v->nattrs*sizeof(*va));
	v->attrs[v->nattrs-1] = *va;
}

static void
copyvattrs(Vertex *d, Vertex *s)
{
	int i;

	for(i = 0; i < s->nattrs; i++)
		_addvattr(d, &s->attrs[i]);
}

Vertex
dupvertex(Vertex *v)
{
	Vertex nv;

	nv = *v;
	nv.attrs = nil;
	nv.nattrs = 0;
	copyvattrs(&nv, v);
	return nv;
}

void
lerpvertex(Vertex *v, Vertex *v0, Vertex *v1, double t)
{
	Vertexattr va;
	int i;

	v->p = lerp3(v0->p, v1->p, t);
	v->n = lerp3(v0->n, v1->n, t);
	v->c = lerp3(v0->c, v1->c, t);
	v->uv = lerp2(v0->uv, v1->uv, t);
	v->attrs = nil;
	v->nattrs = 0;
	for(i = 0; i < v0->nattrs; i++){
		va.id = v0->attrs[i].id;
		va.type = v0->attrs[i].type;
		if(va.type == VAPoint)
			va.p = lerp3(v0->attrs[i].p, v1->attrs[i].p, t);
		else
			va.n = flerp(v0->attrs[i].n, v1->attrs[i].n, t);
		_addvattr(v, &va);
	}
}

/*
 * perspective-correct barycentric attribute interpolation
 */
void
berpvertex(Vertex *v, Vertex *v0, Vertex *v1, Vertex *v2, Point3 bc)
{
	Vertexattr va;
	int i;

	v->n = addpt3(addpt3(
		mulpt3(v0->n, bc.x),
		mulpt3(v1->n, bc.y)),
		mulpt3(v2->n, bc.z));
	v->c = addpt3(addpt3(
		mulpt3(v0->c, bc.x),
		mulpt3(v1->c, bc.y)),
		mulpt3(v2->c, bc.z));
	v->uv = addpt2(addpt2(
		mulpt2(v0->uv, bc.x),
		mulpt2(v1->uv, bc.y)),
		mulpt2(v2->uv, bc.z));
	v->attrs = nil;
	v->nattrs = 0;
	for(i = 0; i < v0->nattrs; i++){
		va.id = v0->attrs[i].id;
		va.type = v0->attrs[i].type;
		if(va.type == VAPoint)
			va.p = addpt3(addpt3(
				mulpt3(v0->attrs[i].p, bc.x),
				mulpt3(v1->attrs[i].p, bc.y)),
				mulpt3(v2->attrs[i].p, bc.z));
		else
			va.n = dotvec3(Vec3(v0->attrs[i].n, v1->attrs[i].n, v2->attrs[i].n), bc);
		_addvattr(v, &va);
	}
}

void
addvattr(Vertex *v, char *id, int type, void *val)
{
	Vertexattr va;

	va.id = id;
	va.type = type;
	switch(type){
	case VAPoint: va.p = *(Point3*)val; break;
	case VANumber: va.n = *(double*)val; break;
	default: sysfatal("unknown vertex attribute type '%d'", type);
	}
	_addvattr(v, &va);
}

Vertexattr *
getvattr(Vertex *v, char *id)
{
	int i;

	for(i = 0; i < v->nattrs; i++)
		if(strcmp(v->attrs[i].id, id) == 0)
			return &v->attrs[i];
	return nil;
}

void
delvattrs(Vertex *v)
{
	free(v->attrs);
	v->attrs= nil;
	v->nattrs = 0;
}

void
fprintvattrs(int fd, Vertex *v)
{
	int i;

	for(i = 0; i < v->nattrs; i++)
		fprint(fd, "id %s type %d v %g\n",
			v->attrs[i].id, v->attrs[i].type, v->attrs[i].n);
}