goat3d

changeset 1:e46529a5d057

some progress
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 17 Aug 2013 23:51:24 +0300
parents 2918358f5e6d
children f358b482d286
files Makefile src/chunk.h src/goat3d_impl.h src/material.h src/mesh.cc src/mesh.h src/opengl.cc src/opengl.h src/vmath.h src/xform_node.cc src/xform_node.h
diffstat 11 files changed, 1887 insertions(+), 33 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Sat Aug 17 16:10:26 2013 +0300
     1.2 +++ b/Makefile	Sat Aug 17 23:51:24 2013 +0300
     1.3 @@ -27,6 +27,7 @@
     1.4  endif
     1.5  
     1.6  CXXFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic)
     1.7 +LDFLAGS = -lvmath -lanim
     1.8  
     1.9  .PHONY: all
    1.10  all: $(lib_so) $(lib_a)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/chunk.h	Sat Aug 17 23:51:24 2013 +0300
     2.3 @@ -0,0 +1,64 @@
     2.4 +#ifndef CHUNK_H_
     2.5 +#define CHUNK_H_
     2.6 +
     2.7 +enum {
     2.8 +	CNK_INVALID,		// this shouldn't appear in files
     2.9 +	CNK_SCENE,			// the root chunk
    2.10 +
    2.11 +	// general purpose chunks
    2.12 +	CNK_INT,
    2.13 +	CNK_UINT,
    2.14 +	CNK_FLOAT,
    2.15 +	CNK_VEC3,
    2.16 +	CNK_VEC4,
    2.17 +	CNK_STRING,
    2.18 +
    2.19 +	// --- first level chunks ---
    2.20 +	// children of CNK_SCENE
    2.21 +	CNK_ENV,			// environmental parameters
    2.22 +	CNK_MTL_LIST,		// material library
    2.23 +	CNK_MESH_LIST,		// all the meshes hang under this chunk
    2.24 +	CNK_LIGHT_LIST,		// likewise for lights
    2.25 +	CNK_CAMERA_LIST,	// likewise for cameras
    2.26 +	CNK_NODE_LIST,		// likewise for nodes
    2.27 +	CNK_ANIM_LIST,		// all animations
    2.28 +
    2.29 +	// --- second level chunks ---
    2.30 +	// children of CNK_ENV
    2.31 +	CNK_ENV_AMBIENT,	// ambient color, contains a single CNK_VEC3
    2.32 +	CNK_ENV_FOG,
    2.33 +
    2.34 +	// children of CNK_*_LIST
    2.35 +	CNK_MTL,
    2.36 +	CNK_MESH,
    2.37 +	CNK_LIGHT,
    2.38 +	CNK_CAMERA,
    2.39 +	CNK_NODE,
    2.40 +
    2.41 +	// --- third level chunks ---
    2.42 +	// children of CNK_FOG
    2.43 +	CNK_FOG_COLOR,		// fog color, contains a single CNK_VEC3
    2.44 +	CNK_FOG_EXP,		// fog exponent, contains a single CNK_REAL
    2.45 +
    2.46 +	// children of CNK_MTL
    2.47 +	CNK_MTL_ATTR,		// material attribute, has a CNK_STRING for its name,
    2.48 +						// a CNK_MTL_ATTR_VAL, and optionally a CNK_MTL_ATTR_MAP
    2.49 +	// children of CNK_MTL_ATTR
    2.50 +	CNK_MTL_ATTR_VAL,	// can have a single CNK_FLOAT, CNK_VEC3, or CNK_VEC4
    2.51 +	CNK_MTL_ATTR_MAP,	// has a single CNK_STRING
    2.52 +
    2.53 +	// children of CNK_MESH
    2.54 +	// TODO...
    2.55 +};
    2.56 +
    2.57 +struct ChunkHeader {
    2.58 +	uint32_t id;
    2.59 +	uint32_t size;
    2.60 +};
    2.61 +
    2.62 +struct Chunk {
    2.63 +	ChunkHeader hdr;
    2.64 +	char data[1];
    2.65 +};
    2.66 +
    2.67 +#endif	// CHUNK_H_
     3.1 --- a/src/goat3d_impl.h	Sat Aug 17 16:10:26 2013 +0300
     3.2 +++ b/src/goat3d_impl.h	Sat Aug 17 23:51:24 2013 +0300
     3.3 @@ -2,8 +2,8 @@
     3.4  #define GOAT3D_IMPL_H_
     3.5  
     3.6  #include <string>
     3.7 +#include <vmath/vmath.h>
     3.8  #include "goat3d.h"
     3.9 -#include "vmath.h"
    3.10  #include "mesh.h"
    3.11  #include "light.h"
    3.12  #include "camera.h"
     4.1 --- a/src/material.h	Sat Aug 17 16:10:26 2013 +0300
     4.2 +++ b/src/material.h	Sat Aug 17 23:51:24 2013 +0300
     4.3 @@ -1,8 +1,44 @@
     4.4  #ifndef MATERIAL_H_
     4.5  #define MATERIAL_H_
     4.6  
     4.7 +#include <string>
     4.8 +#include <map>
     4.9 +#include <vmath/vmath.h>
    4.10 +
    4.11 +struct MaterialAttrib {
    4.12 +	Vector4 value;
    4.13 +	std::string map;
    4.14 +};
    4.15 +
    4.16 +#define MAT_ATTR_DIFFUSE		"diffuse"
    4.17 +#define MAT_ATTR_SPECULAR		"specular"
    4.18 +#define MAT_ATTR_SHININESS		"shininess"
    4.19 +#define MAT_ATTR_NORMAL			"normal"
    4.20 +#define MAT_ATTR_BUMP			"bump"
    4.21 +#define MAT_ATTR_REFLECTION		"reflection"
    4.22 +#define MAT_ATTR_TRANSMISSION	"transmission"
    4.23 +#define MAT_ATTR_IOR			"ior"
    4.24 +
    4.25  class Material {
    4.26 -	// TODO
    4.27 +private:
    4.28 +	static MaterialAttrib def_attr;
    4.29 +
    4.30 +	std::map<std::string, MaterialAttrib> attrib;
    4.31 +
    4.32 +public:
    4.33 +	MaterialAttrib &operator [](const std::string &name)
    4.34 +	{
    4.35 +		return attrib[name];
    4.36 +	}
    4.37 +
    4.38 +	const MaterialAttrib &operator [](const std::string &name) const
    4.39 +	{
    4.40 +		std::map<std::string, MaterialAttrib>::const_iterator it;
    4.41 +		if((it = attrib.find(name)) != attrib.end()) {
    4.42 +			return it->second;
    4.43 +		}
    4.44 +		return def_attr;
    4.45 +	}
    4.46  };
    4.47  
    4.48  #endif	// MATERIAL_H_
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/mesh.cc	Sat Aug 17 23:51:24 2013 +0300
     5.3 @@ -0,0 +1,973 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include <float.h>
     5.7 +#include <assert.h>
     5.8 +#include "opengl.h"
     5.9 +#include "mesh.h"
    5.10 +#include "xform_node.h"
    5.11 +//#include "logger.h"
    5.12 +
    5.13 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 };
    5.14 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
    5.15 +float Mesh::vertex_sel_dist = 0.01;
    5.16 +float Mesh::vis_vecsize = 1.0;
    5.17 +
    5.18 +Mesh::Mesh()
    5.19 +{
    5.20 +	clear();
    5.21 +
    5.22 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
    5.23 +
    5.24 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
    5.25 +		vattr[i].vbo = buffer_objects[i];
    5.26 +	}
    5.27 +	ibo = buffer_objects[NUM_MESH_ATTR];
    5.28 +	wire_ibo = 0;
    5.29 +}
    5.30 +
    5.31 +Mesh::~Mesh()
    5.32 +{
    5.33 +	glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
    5.34 +
    5.35 +	if(wire_ibo) {
    5.36 +		glDeleteBuffers(1, &wire_ibo);
    5.37 +	}
    5.38 +}
    5.39 +
    5.40 +void Mesh::set_name(const char *name)
    5.41 +{
    5.42 +	this->name = name;
    5.43 +}
    5.44 +
    5.45 +const char *Mesh::get_name() const
    5.46 +{
    5.47 +	return name.c_str();
    5.48 +}
    5.49 +
    5.50 +bool Mesh::has_attrib(int attr) const
    5.51 +{
    5.52 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
    5.53 +		return false;
    5.54 +	}
    5.55 +
    5.56 +	// if neither of these is valid, then nobody has set this attribute
    5.57 +	return vattr[attr].vbo_valid || vattr[attr].data_valid;
    5.58 +}
    5.59 +
    5.60 +void Mesh::clear()
    5.61 +{
    5.62 +	bones.clear();
    5.63 +
    5.64 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
    5.65 +		vattr[i].nelem = 0;
    5.66 +		vattr[i].vbo_valid = false;
    5.67 +		vattr[i].data_valid = false;
    5.68 +		//vattr[i].sdr_loc = -1;
    5.69 +		vattr[i].data.clear();
    5.70 +	}
    5.71 +	ibo_valid = false;
    5.72 +	idata.clear();
    5.73 +
    5.74 +	wire_ibo_valid = false;
    5.75 +
    5.76 +	nverts = nfaces = 0;
    5.77 +
    5.78 +	/*bsph_valid = false;
    5.79 +	aabb_valid = false;*/
    5.80 +}
    5.81 +
    5.82 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
    5.83 +{
    5.84 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
    5.85 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
    5.86 +		return 0;
    5.87 +	}
    5.88 +
    5.89 +	if(nverts && num != nverts) {
    5.90 +		fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
    5.91 +		return 0;
    5.92 +	}
    5.93 +	nverts = num;
    5.94 +
    5.95 +	vattr[attrib].data.clear();
    5.96 +	vattr[attrib].nelem = nelem;
    5.97 +	vattr[attrib].data.resize(num * nelem);
    5.98 +
    5.99 +	if(data) {
   5.100 +		memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
   5.101 +	}
   5.102 +
   5.103 +	vattr[attrib].data_valid = true;
   5.104 +	vattr[attrib].vbo_valid = false;
   5.105 +	return &vattr[attrib].data[0];
   5.106 +}
   5.107 +
   5.108 +float *Mesh::get_attrib_data(int attrib)
   5.109 +{
   5.110 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
   5.111 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
   5.112 +		return 0;
   5.113 +	}
   5.114 +
   5.115 +	vattr[attrib].vbo_valid = false;
   5.116 +	return (float*)((const Mesh*)this)->get_attrib_data(attrib);
   5.117 +}
   5.118 +
   5.119 +const float *Mesh::get_attrib_data(int attrib) const
   5.120 +{
   5.121 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
   5.122 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
   5.123 +		return 0;
   5.124 +	}
   5.125 +
   5.126 +	if(!vattr[attrib].data_valid) {
   5.127 +#if GL_ES_VERSION_2_0
   5.128 +		fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
   5.129 +		return 0;
   5.130 +#else
   5.131 +		if(!vattr[attrib].vbo_valid) {
   5.132 +			fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
   5.133 +			return 0;
   5.134 +		}
   5.135 +
   5.136 +		// local data copy is unavailable, grab the data from the vbo
   5.137 +		Mesh *m = (Mesh*)this;
   5.138 +		m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
   5.139 +
   5.140 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
   5.141 +		void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
   5.142 +		memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
   5.143 +		glUnmapBuffer(GL_ARRAY_BUFFER);
   5.144 +
   5.145 +		vattr[attrib].data_valid = true;
   5.146 +#endif
   5.147 +	}
   5.148 +
   5.149 +	return &vattr[attrib].data[0];
   5.150 +}
   5.151 +
   5.152 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
   5.153 +{
   5.154 +	float *data = get_attrib_data(attrib);
   5.155 +	if(data) {
   5.156 +		data += idx * vattr[attrib].nelem;
   5.157 +		for(int i=0; i<vattr[attrib].nelem; i++) {
   5.158 +			data[i] = v[i];
   5.159 +		}
   5.160 +	}
   5.161 +}
   5.162 +
   5.163 +Vector4 Mesh::get_attrib(int attrib, int idx) const
   5.164 +{
   5.165 +	Vector4 v(0.0, 0.0, 0.0, 1.0);
   5.166 +	const float *data = get_attrib_data(attrib);
   5.167 +	if(data) {
   5.168 +		data += idx * vattr[attrib].nelem;
   5.169 +		for(int i=0; i<vattr[attrib].nelem; i++) {
   5.170 +			v[i] = data[i];
   5.171 +		}
   5.172 +	}
   5.173 +	return v;
   5.174 +}
   5.175 +
   5.176 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
   5.177 +{
   5.178 +	int nidx = nfaces * 3;
   5.179 +	if(nidx && num != nidx) {
   5.180 +		fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
   5.181 +		return 0;
   5.182 +	}
   5.183 +	nfaces = num / 3;
   5.184 +
   5.185 +	idata.clear();
   5.186 +	idata.resize(num);
   5.187 +
   5.188 +	if(indices) {
   5.189 +		memcpy(&idata[0], indices, num * sizeof *indices);
   5.190 +	}
   5.191 +
   5.192 +	idata_valid = true;
   5.193 +	ibo_valid = false;
   5.194 +
   5.195 +	return &idata[0];
   5.196 +}
   5.197 +
   5.198 +unsigned int *Mesh::get_index_data()
   5.199 +{
   5.200 +	ibo_valid = false;
   5.201 +	return (unsigned int*)((const Mesh*)this)->get_index_data();
   5.202 +}
   5.203 +
   5.204 +const unsigned int *Mesh::get_index_data() const
   5.205 +{
   5.206 +	if(!idata_valid) {
   5.207 +#if GL_ES_VERSION_2_0
   5.208 +		fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
   5.209 +		return 0;
   5.210 +#else
   5.211 +		if(!ibo_valid) {
   5.212 +			fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
   5.213 +			return 0;
   5.214 +		}
   5.215 +
   5.216 +		// local data copy is unavailable, gram the data from the ibo
   5.217 +		Mesh *m = (Mesh*)this;
   5.218 +		int nidx = nfaces * 3;
   5.219 +		m->idata.resize(nidx);
   5.220 +
   5.221 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
   5.222 +		void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
   5.223 +		memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
   5.224 +		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
   5.225 +
   5.226 +		idata_valid = true;
   5.227 +#endif
   5.228 +	}
   5.229 +
   5.230 +	return &idata[0];
   5.231 +}
   5.232 +
   5.233 +void Mesh::append(const Mesh &mesh)
   5.234 +{
   5.235 +	unsigned int idxoffs = nverts;
   5.236 +
   5.237 +	nverts += mesh.nverts;
   5.238 +	nfaces += mesh.nfaces;
   5.239 +
   5.240 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.241 +		if(has_attrib(i) && mesh.has_attrib(i)) {
   5.242 +			// force validating the data arrays
   5.243 +			get_attrib_data(i);
   5.244 +			mesh.get_attrib_data(i);
   5.245 +
   5.246 +			// append the mesh data
   5.247 +			vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
   5.248 +		}
   5.249 +	}
   5.250 +
   5.251 +	if(ibo_valid || idata_valid) {
   5.252 +		// make index arrays valid
   5.253 +		get_index_data();
   5.254 +		mesh.get_index_data();
   5.255 +
   5.256 +		size_t orig_sz = idata.size();
   5.257 +
   5.258 +		idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
   5.259 +
   5.260 +		// fixup all the new indices
   5.261 +		for(size_t i=orig_sz; i<idata.size(); i++) {
   5.262 +			idata[i] += idxoffs;
   5.263 +		}
   5.264 +	}
   5.265 +
   5.266 +	// fuck everything
   5.267 +	wire_ibo_valid = false;
   5.268 +	/*aabb_valid = false;
   5.269 +	bsph_valid = false;*/
   5.270 +}
   5.271 +
   5.272 +// assemble a complete vertex by adding all the useful attributes
   5.273 +void Mesh::vertex(float x, float y, float z)
   5.274 +{
   5.275 +	cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
   5.276 +	vattr[MESH_ATTR_VERTEX].data_valid = true;
   5.277 +	vattr[MESH_ATTR_VERTEX].nelem = 3;
   5.278 +
   5.279 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.280 +		if(vattr[i].data_valid) {
   5.281 +			for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
   5.282 +				vattr[i].data.push_back(cur_val[i][j]);
   5.283 +			}
   5.284 +		}
   5.285 +		vattr[i].vbo_valid = false;
   5.286 +	}
   5.287 +
   5.288 +	if(idata_valid) {
   5.289 +		idata.clear();
   5.290 +	}
   5.291 +	ibo_valid = idata_valid = false;
   5.292 +}
   5.293 +
   5.294 +void Mesh::normal(float nx, float ny, float nz)
   5.295 +{
   5.296 +	cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
   5.297 +	vattr[MESH_ATTR_NORMAL].data_valid = true;
   5.298 +	vattr[MESH_ATTR_NORMAL].nelem = 3;
   5.299 +}
   5.300 +
   5.301 +void Mesh::tangent(float tx, float ty, float tz)
   5.302 +{
   5.303 +	cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
   5.304 +	vattr[MESH_ATTR_TANGENT].data_valid = true;
   5.305 +	vattr[MESH_ATTR_TANGENT].nelem = 3;
   5.306 +}
   5.307 +
   5.308 +void Mesh::texcoord(float u, float v, float w)
   5.309 +{
   5.310 +	cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
   5.311 +	vattr[MESH_ATTR_TEXCOORD].data_valid = true;
   5.312 +	vattr[MESH_ATTR_TEXCOORD].nelem = 3;
   5.313 +}
   5.314 +
   5.315 +void Mesh::boneweights(float w1, float w2, float w3, float w4)
   5.316 +{
   5.317 +	cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
   5.318 +	vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
   5.319 +	vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
   5.320 +}
   5.321 +
   5.322 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
   5.323 +{
   5.324 +	cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
   5.325 +	vattr[MESH_ATTR_BONEIDX].data_valid = true;
   5.326 +	vattr[MESH_ATTR_BONEIDX].nelem = 4;
   5.327 +}
   5.328 +
   5.329 +/// static function
   5.330 +void Mesh::set_attrib_location(int attr, int loc)
   5.331 +{
   5.332 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
   5.333 +		return;
   5.334 +	}
   5.335 +	Mesh::global_sdr_loc[attr] = loc;
   5.336 +}
   5.337 +
   5.338 +/// static function
   5.339 +int Mesh::get_attrib_location(int attr)
   5.340 +{
   5.341 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
   5.342 +		return -1;
   5.343 +	}
   5.344 +	return Mesh::global_sdr_loc[attr];
   5.345 +}
   5.346 +
   5.347 +/// static function
   5.348 +void Mesh::clear_attrib_locations()
   5.349 +{
   5.350 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.351 +		Mesh::global_sdr_loc[i] = -1;
   5.352 +	}
   5.353 +}
   5.354 +
   5.355 +/// static function
   5.356 +void Mesh::set_vis_vecsize(float sz)
   5.357 +{
   5.358 +	Mesh::vis_vecsize = sz;
   5.359 +}
   5.360 +
   5.361 +float Mesh::get_vis_vecsize()
   5.362 +{
   5.363 +	return Mesh::vis_vecsize;
   5.364 +}
   5.365 +
   5.366 +void Mesh::apply_xform(const Matrix4x4 &xform)
   5.367 +{
   5.368 +	Matrix4x4 dir_xform = xform;
   5.369 +	dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
   5.370 +	dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
   5.371 +	dir_xform[3][3] = 1.0f;
   5.372 +
   5.373 +	apply_xform(xform, dir_xform);
   5.374 +}
   5.375 +
   5.376 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
   5.377 +{
   5.378 +	for(unsigned int i=0; i<nverts; i++) {
   5.379 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
   5.380 +		set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
   5.381 +
   5.382 +		if(has_attrib(MESH_ATTR_NORMAL)) {
   5.383 +			Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
   5.384 +			set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
   5.385 +		}
   5.386 +		if(has_attrib(MESH_ATTR_TANGENT)) {
   5.387 +			Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
   5.388 +			set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
   5.389 +		}
   5.390 +	}
   5.391 +}
   5.392 +
   5.393 +int Mesh::add_bone(XFormNode *bone)
   5.394 +{
   5.395 +	int idx = bones.size();
   5.396 +	bones.push_back(bone);
   5.397 +	return idx;
   5.398 +}
   5.399 +
   5.400 +const XFormNode *Mesh::get_bone(int idx) const
   5.401 +{
   5.402 +	if(idx < 0 || idx >= (int)bones.size()) {
   5.403 +		return 0;
   5.404 +	}
   5.405 +	return bones[idx];
   5.406 +}
   5.407 +
   5.408 +int Mesh::get_bones_count() const
   5.409 +{
   5.410 +	return (int)bones.size();
   5.411 +}
   5.412 +
   5.413 +void Mesh::draw() const
   5.414 +{
   5.415 +	((Mesh*)this)->update_buffers();
   5.416 +
   5.417 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
   5.418 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
   5.419 +		return;
   5.420 +	}
   5.421 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
   5.422 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
   5.423 +		return;
   5.424 +	}
   5.425 +
   5.426 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.427 +		int loc = global_sdr_loc[i];
   5.428 +		if(loc >= 0 && vattr[i].vbo_valid) {
   5.429 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
   5.430 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
   5.431 +			glEnableVertexAttribArray(loc);
   5.432 +		}
   5.433 +	}
   5.434 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
   5.435 +
   5.436 +	if(ibo_valid) {
   5.437 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
   5.438 +		glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
   5.439 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   5.440 +	} else {
   5.441 +		glDrawArrays(GL_TRIANGLES, 0, nverts);
   5.442 +	}
   5.443 +
   5.444 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.445 +		int loc = global_sdr_loc[i];
   5.446 +		if(loc >= 0 && vattr[i].vbo_valid) {
   5.447 +			glDisableVertexAttribArray(loc);
   5.448 +		}
   5.449 +	}
   5.450 +}
   5.451 +
   5.452 +void Mesh::draw_wire() const
   5.453 +{
   5.454 +	((Mesh*)this)->update_wire_ibo();
   5.455 +
   5.456 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
   5.457 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
   5.458 +		return;
   5.459 +	}
   5.460 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
   5.461 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
   5.462 +		return;
   5.463 +	}
   5.464 +
   5.465 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.466 +		int loc = global_sdr_loc[i];
   5.467 +		if(loc >= 0 && vattr[i].vbo_valid) {
   5.468 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
   5.469 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
   5.470 +			glEnableVertexAttribArray(loc);
   5.471 +		}
   5.472 +	}
   5.473 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
   5.474 +
   5.475 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
   5.476 +	glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
   5.477 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   5.478 +
   5.479 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.480 +		int loc = global_sdr_loc[i];
   5.481 +		if(loc >= 0 && vattr[i].vbo_valid) {
   5.482 +			glDisableVertexAttribArray(loc);
   5.483 +		}
   5.484 +	}
   5.485 +}
   5.486 +
   5.487 +void Mesh::draw_vertices() const
   5.488 +{
   5.489 +	((Mesh*)this)->update_buffers();
   5.490 +
   5.491 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
   5.492 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
   5.493 +		return;
   5.494 +	}
   5.495 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
   5.496 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
   5.497 +		return;
   5.498 +	}
   5.499 +
   5.500 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.501 +		int loc = global_sdr_loc[i];
   5.502 +		if(loc >= 0 && vattr[i].vbo_valid) {
   5.503 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
   5.504 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
   5.505 +			glEnableVertexAttribArray(loc);
   5.506 +		}
   5.507 +	}
   5.508 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
   5.509 +
   5.510 +	glDrawArrays(GL_POINTS, 0, nverts);
   5.511 +
   5.512 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.513 +		int loc = global_sdr_loc[i];
   5.514 +		if(loc >= 0 && vattr[i].vbo_valid) {
   5.515 +			glDisableVertexAttribArray(loc);
   5.516 +		}
   5.517 +	}
   5.518 +}
   5.519 +
   5.520 +void Mesh::draw_normals() const
   5.521 +{
   5.522 +#ifdef USE_OLDGL
   5.523 +	int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
   5.524 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
   5.525 +	Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
   5.526 +
   5.527 +	if(!varr || !norm || vert_loc < 0) {
   5.528 +		return;
   5.529 +	}
   5.530 +
   5.531 +	glBegin(GL_LINES);
   5.532 +	for(size_t i=0; i<nverts; i++) {
   5.533 +		glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
   5.534 +		Vector3 end = varr[i] + norm[i] * vis_vecsize;
   5.535 +		glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
   5.536 +	}
   5.537 +	glEnd();
   5.538 +
   5.539 +#endif	// USE_OLDGL
   5.540 +}
   5.541 +
   5.542 +void Mesh::draw_tangents() const
   5.543 +{
   5.544 +#ifdef USE_OLDGL
   5.545 +	int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
   5.546 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
   5.547 +	Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
   5.548 +
   5.549 +	if(!varr || !tang || vert_loc < 0) {
   5.550 +		return;
   5.551 +	}
   5.552 +
   5.553 +	glBegin(GL_LINES);
   5.554 +	for(size_t i=0; i<nverts; i++) {
   5.555 +		glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
   5.556 +		Vector3 end = varr[i] + tang[i] * vis_vecsize;
   5.557 +		glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
   5.558 +	}
   5.559 +	glEnd();
   5.560 +
   5.561 +#endif	// USE_OLDGL
   5.562 +}
   5.563 +
   5.564 +#if 0
   5.565 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
   5.566 +{
   5.567 +	if(!aabb_valid) {
   5.568 +		((Mesh*)this)->calc_aabb();
   5.569 +	}
   5.570 +	*vmin = aabb.min;
   5.571 +	*vmax = aabb.max;
   5.572 +}
   5.573 +
   5.574 +const AABox &Mesh::get_aabbox() const
   5.575 +{
   5.576 +	if(!aabb_valid) {
   5.577 +		((Mesh*)this)->calc_aabb();
   5.578 +	}
   5.579 +	return aabb;
   5.580 +}
   5.581 +
   5.582 +float Mesh::get_bsphere(Vector3 *center, float *rad) const
   5.583 +{
   5.584 +	if(!bsph_valid) {
   5.585 +		((Mesh*)this)->calc_bsph();
   5.586 +	}
   5.587 +	*center = bsph.center;
   5.588 +	*rad = bsph.radius;
   5.589 +	return bsph.radius;
   5.590 +}
   5.591 +
   5.592 +const Sphere &Mesh::get_bsphere() const
   5.593 +{
   5.594 +	if(!bsph_valid) {
   5.595 +		((Mesh*)this)->calc_bsph();
   5.596 +	}
   5.597 +	return bsph;
   5.598 +}
   5.599 +
   5.600 +/// static function
   5.601 +void Mesh::set_intersect_mode(unsigned int mode)
   5.602 +{
   5.603 +	Mesh::intersect_mode = mode;
   5.604 +}
   5.605 +
   5.606 +/// static function
   5.607 +unsigned int Mesh::get_intersect_mode()
   5.608 +{
   5.609 +	return Mesh::intersect_mode;
   5.610 +}
   5.611 +
   5.612 +/// static function
   5.613 +void Mesh::set_vertex_select_distance(float dist)
   5.614 +{
   5.615 +	Mesh::vertex_sel_dist = dist;
   5.616 +}
   5.617 +
   5.618 +/// static function
   5.619 +float Mesh::get_vertex_select_distance()
   5.620 +{
   5.621 +	return Mesh::vertex_sel_dist;
   5.622 +}
   5.623 +
   5.624 +/*bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
   5.625 +{
   5.626 +	assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
   5.627 +
   5.628 +	const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
   5.629 +	const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
   5.630 +	if(!varr) {
   5.631 +		return false;
   5.632 +	}
   5.633 +	const unsigned int *idxarr = get_index_data();
   5.634 +
   5.635 +	// first test with the bounding box
   5.636 +	AABox box;
   5.637 +	get_aabbox(&box.min, &box.max);
   5.638 +	if(!box.intersect(ray)) {
   5.639 +		return false;
   5.640 +	}
   5.641 +
   5.642 +	HitPoint nearest_hit;
   5.643 +	nearest_hit.dist = FLT_MAX;
   5.644 +	nearest_hit.obj = 0;
   5.645 +
   5.646 +	if(Mesh::intersect_mode & ISECT_VERTICES) {
   5.647 +		// we asked for "intersections" with the vertices of the mesh
   5.648 +		long nearest_vidx = -1;
   5.649 +		float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
   5.650 +
   5.651 +		for(unsigned int i=0; i<nverts; i++) {
   5.652 +
   5.653 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
   5.654 +				continue;
   5.655 +			}
   5.656 +
   5.657 +			// project the vertex onto the ray line
   5.658 +			float t = dot_product(varr[i] - ray.origin, ray.dir);
   5.659 +			Vector3 vproj = ray.origin + ray.dir * t;
   5.660 +
   5.661 +			float dist_sq = (vproj - varr[i]).length_sq();
   5.662 +			if(dist_sq < thres_sq) {
   5.663 +				if(!hit) {
   5.664 +					return true;
   5.665 +				}
   5.666 +				if(t < nearest_hit.dist) {
   5.667 +					nearest_hit.dist = t;
   5.668 +					nearest_vidx = i;
   5.669 +				}
   5.670 +			}
   5.671 +		}
   5.672 +
   5.673 +		if(nearest_vidx != -1) {
   5.674 +			hitvert = varr[nearest_vidx];
   5.675 +			nearest_hit.obj = &hitvert;
   5.676 +		}
   5.677 +
   5.678 +	} else {
   5.679 +		// regular intersection test with polygons
   5.680 +
   5.681 +		for(unsigned int i=0; i<nfaces; i++) {
   5.682 +			Triangle face(i, varr, idxarr);
   5.683 +
   5.684 +			// ignore back-facing polygons if the mode flags include ISECT_FRONT
   5.685 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
   5.686 +				continue;
   5.687 +			}
   5.688 +
   5.689 +			HitPoint fhit;
   5.690 +			if(face.intersect(ray, hit ? &fhit : 0)) {
   5.691 +				if(!hit) {
   5.692 +					return true;
   5.693 +				}
   5.694 +				if(fhit.dist < nearest_hit.dist) {
   5.695 +					nearest_hit = fhit;
   5.696 +					hitface = face;
   5.697 +				}
   5.698 +			}
   5.699 +		}
   5.700 +	}
   5.701 +
   5.702 +	if(nearest_hit.obj) {
   5.703 +		if(hit) {
   5.704 +			*hit = nearest_hit;
   5.705 +
   5.706 +			// if we are interested in the mesh and not the faces set obj to this
   5.707 +			if(Mesh::intersect_mode & ISECT_FACE) {
   5.708 +				hit->obj = &hitface;
   5.709 +			} else if(Mesh::intersect_mode & ISECT_VERTICES) {
   5.710 +				hit->obj = &hitvert;
   5.711 +			} else {
   5.712 +				hit->obj = this;
   5.713 +			}
   5.714 +		}
   5.715 +		return true;
   5.716 +	}
   5.717 +	return false;
   5.718 +}*/
   5.719 +
   5.720 +
   5.721 +// ------ private member functions ------
   5.722 +
   5.723 +void Mesh::calc_aabb()
   5.724 +{
   5.725 +	// the cast is to force calling the const version which doesn't invalidate
   5.726 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
   5.727 +		return;
   5.728 +	}
   5.729 +
   5.730 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
   5.731 +	aabb.max = -aabb.min;
   5.732 +
   5.733 +	for(unsigned int i=0; i<nverts; i++) {
   5.734 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
   5.735 +		for(int j=0; j<3; j++) {
   5.736 +			if(v[j] < aabb.min[j]) {
   5.737 +				aabb.min[j] = v[j];
   5.738 +			}
   5.739 +			if(v[j] > aabb.max[j]) {
   5.740 +				aabb.max[j] = v[j];
   5.741 +			}
   5.742 +		}
   5.743 +	}
   5.744 +	aabb_valid = true;
   5.745 +}
   5.746 +
   5.747 +void Mesh::calc_bsph()
   5.748 +{
   5.749 +	// the cast is to force calling the const version which doesn't invalidate
   5.750 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
   5.751 +		return;
   5.752 +	}
   5.753 +
   5.754 +	Vector3 v;
   5.755 +	bsph.center = Vector3(0, 0, 0);
   5.756 +
   5.757 +	// first find the center
   5.758 +	for(unsigned int i=0; i<nverts; i++) {
   5.759 +		v = get_attrib(MESH_ATTR_VERTEX, i);
   5.760 +		bsph.center += v;
   5.761 +	}
   5.762 +	bsph.center /= (float)nverts;
   5.763 +
   5.764 +	bsph.radius = 0.0f;
   5.765 +	for(unsigned int i=0; i<nverts; i++) {
   5.766 +		v = get_attrib(MESH_ATTR_VERTEX, i);
   5.767 +		float dist_sq = (v - bsph.center).length_sq();
   5.768 +		if(dist_sq > bsph.radius) {
   5.769 +			bsph.radius = dist_sq;
   5.770 +		}
   5.771 +	}
   5.772 +	bsph.radius = sqrt(bsph.radius);
   5.773 +
   5.774 +	bsph_valid = true;
   5.775 +}
   5.776 +#endif
   5.777 +
   5.778 +void Mesh::update_buffers()
   5.779 +{
   5.780 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   5.781 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
   5.782 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
   5.783 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
   5.784 +			vattr[i].vbo_valid = true;
   5.785 +		}
   5.786 +	}
   5.787 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
   5.788 +
   5.789 +	if(idata_valid && !ibo_valid) {
   5.790 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
   5.791 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
   5.792 +		ibo_valid = true;
   5.793 +	}
   5.794 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   5.795 +}
   5.796 +
   5.797 +void Mesh::update_wire_ibo()
   5.798 +{
   5.799 +	update_buffers();
   5.800 +
   5.801 +	if(wire_ibo_valid) {
   5.802 +		return;
   5.803 +	}
   5.804 +
   5.805 +	if(!wire_ibo) {
   5.806 +		glGenBuffers(1, &wire_ibo);
   5.807 +	}
   5.808 +
   5.809 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
   5.810 +	unsigned int *dest = wire_idxarr;
   5.811 +
   5.812 +	if(ibo_valid) {
   5.813 +		// we're dealing with an indexed mesh
   5.814 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
   5.815 +
   5.816 +		for(unsigned int i=0; i<nfaces; i++) {
   5.817 +			*dest++ = idxarr[0];
   5.818 +			*dest++ = idxarr[1];
   5.819 +			*dest++ = idxarr[1];
   5.820 +			*dest++ = idxarr[2];
   5.821 +			*dest++ = idxarr[2];
   5.822 +			*dest++ = idxarr[0];
   5.823 +			idxarr += 3;
   5.824 +		}
   5.825 +	} else {
   5.826 +		// not an indexed mesh ...
   5.827 +		for(unsigned int i=0; i<nfaces; i++) {
   5.828 +			int vidx = i * 3;
   5.829 +			*dest++ = vidx;
   5.830 +			*dest++ = vidx + 1;
   5.831 +			*dest++ = vidx + 1;
   5.832 +			*dest++ = vidx + 2;
   5.833 +			*dest++ = vidx + 2;
   5.834 +			*dest++ = vidx;
   5.835 +		}
   5.836 +	}
   5.837 +
   5.838 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
   5.839 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
   5.840 +	delete [] wire_idxarr;
   5.841 +	wire_ibo_valid = true;
   5.842 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   5.843 +}
   5.844 +
   5.845 +
   5.846 +// ------ class Triangle ------
   5.847 +Triangle::Triangle()
   5.848 +{
   5.849 +	normal_valid = false;
   5.850 +	id = -1;
   5.851 +}
   5.852 +
   5.853 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
   5.854 +{
   5.855 +	v[0] = v0;
   5.856 +	v[1] = v1;
   5.857 +	v[2] = v2;
   5.858 +	normal_valid = false;
   5.859 +	id = -1;
   5.860 +}
   5.861 +
   5.862 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
   5.863 +{
   5.864 +	if(idxarr) {
   5.865 +		v[0] = varr[idxarr[n * 3]];
   5.866 +		v[1] = varr[idxarr[n * 3 + 1]];
   5.867 +		v[2] = varr[idxarr[n * 3 + 2]];
   5.868 +	} else {
   5.869 +		v[0] = varr[n * 3];
   5.870 +		v[1] = varr[n * 3 + 1];
   5.871 +		v[2] = varr[n * 3 + 2];
   5.872 +	}
   5.873 +	normal_valid = false;
   5.874 +	id = n;
   5.875 +}
   5.876 +
   5.877 +void Triangle::calc_normal()
   5.878 +{
   5.879 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
   5.880 +	normal_valid = true;
   5.881 +}
   5.882 +
   5.883 +const Vector3 &Triangle::get_normal() const
   5.884 +{
   5.885 +	if(!normal_valid) {
   5.886 +		((Triangle*)this)->calc_normal();
   5.887 +	}
   5.888 +	return normal;
   5.889 +}
   5.890 +
   5.891 +void Triangle::transform(const Matrix4x4 &xform)
   5.892 +{
   5.893 +	v[0].transform(xform);
   5.894 +	v[1].transform(xform);
   5.895 +	v[2].transform(xform);
   5.896 +	normal_valid = false;
   5.897 +}
   5.898 +
   5.899 +void Triangle::draw() const
   5.900 +{
   5.901 +	Vector3 n[3];
   5.902 +	n[0] = get_normal();
   5.903 +	n[1] = get_normal();
   5.904 +	n[2] = get_normal();
   5.905 +
   5.906 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
   5.907 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
   5.908 +
   5.909 +	glEnableVertexAttribArray(vloc);
   5.910 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
   5.911 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
   5.912 +
   5.913 +	glDrawArrays(GL_TRIANGLES, 0, 3);
   5.914 +
   5.915 +	glDisableVertexAttribArray(vloc);
   5.916 +	glDisableVertexAttribArray(nloc);
   5.917 +	CHECKGLERR;
   5.918 +}
   5.919 +
   5.920 +void Triangle::draw_wire() const
   5.921 +{
   5.922 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
   5.923 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
   5.924 +
   5.925 +	glEnableVertexAttribArray(vloc);
   5.926 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
   5.927 +
   5.928 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
   5.929 +
   5.930 +	glDisableVertexAttribArray(vloc);
   5.931 +	CHECKGLERR;
   5.932 +}
   5.933 +
   5.934 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
   5.935 +{
   5.936 +	Vector3 norm = get_normal();
   5.937 +
   5.938 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
   5.939 +	if(area_sq < 1e-5) {
   5.940 +		return Vector3(0, 0, 0);
   5.941 +	}
   5.942 +
   5.943 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
   5.944 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
   5.945 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
   5.946 +
   5.947 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
   5.948 +}
   5.949 +
   5.950 +/*bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
   5.951 +{
   5.952 +	Vector3 normal = get_normal();
   5.953 +
   5.954 +	float ndotdir = dot_product(ray.dir, normal);
   5.955 +	if(fabs(ndotdir) < 1e-4) {
   5.956 +		return false;
   5.957 +	}
   5.958 +
   5.959 +	Vector3 vertdir = v[0] - ray.origin;
   5.960 +	float t = dot_product(normal, vertdir) / ndotdir;
   5.961 +
   5.962 +	Vector3 pos = ray.origin + ray.dir * t;
   5.963 +	Vector3 bary = calc_barycentric(pos);
   5.964 +
   5.965 +	if(bary.x + bary.y + bary.z > 1.00001) {
   5.966 +		return false;
   5.967 +	}
   5.968 +
   5.969 +	if(hit) {
   5.970 +		hit->dist = t;
   5.971 +		hit->pos = ray.origin + ray.dir * t;
   5.972 +		hit->normal = normal;
   5.973 +		hit->obj = this;
   5.974 +	}
   5.975 +	return true;
   5.976 +}*/
     6.1 --- a/src/mesh.h	Sat Aug 17 16:10:26 2013 +0300
     6.2 +++ b/src/mesh.h	Sat Aug 17 23:51:24 2013 +0300
     6.3 @@ -1,8 +1,213 @@
     6.4  #ifndef MESH_H_
     6.5  #define MESH_H_
     6.6  
     6.7 -class Mesh {
     6.8 -	// TODO
     6.9 +#include <string>
    6.10 +#include <vector>
    6.11 +#include <vmath/vmath.h>
    6.12 +//#include "geom.h"
    6.13 +
    6.14 +enum {
    6.15 +	MESH_ATTR_VERTEX,
    6.16 +	MESH_ATTR_NORMAL,
    6.17 +	MESH_ATTR_TANGENT,
    6.18 +	MESH_ATTR_TEXCOORD,
    6.19 +	MESH_ATTR_COLOR,
    6.20 +	MESH_ATTR_BONEWEIGHTS,
    6.21 +	MESH_ATTR_BONEIDX,
    6.22 +
    6.23 +	NUM_MESH_ATTR
    6.24  };
    6.25  
    6.26 +// intersection mode flags
    6.27 +enum {
    6.28 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
    6.29 +	ISECT_FRONT		= 1,	// front-faces only
    6.30 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
    6.31 +	ISECT_VERTICES	= 4		// return (?) TODO
    6.32 +};
    6.33 +
    6.34 +class XFormNode;
    6.35 +
    6.36 +
    6.37 +class Triangle {
    6.38 +public:
    6.39 +	Vector3 v[3];
    6.40 +	Vector3 normal;
    6.41 +	bool normal_valid;
    6.42 +	int id;
    6.43 +
    6.44 +	Triangle();
    6.45 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
    6.46 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
    6.47 +
    6.48 +	/// calculate normal (quite expensive)
    6.49 +	void calc_normal();
    6.50 +	const Vector3 &get_normal() const;
    6.51 +
    6.52 +	void transform(const Matrix4x4 &xform);
    6.53 +
    6.54 +	void draw() const;
    6.55 +	void draw_wire() const;
    6.56 +
    6.57 +	/// calculate barycentric coordinates of a point
    6.58 +	Vector3 calc_barycentric(const Vector3 &pos) const;
    6.59 +
    6.60 +	//bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    6.61 +};
    6.62 +
    6.63 +
    6.64 +class Mesh {
    6.65 +private:
    6.66 +	std::string name;
    6.67 +	unsigned int nverts, nfaces;
    6.68 +
    6.69 +	// current value for each attribute for the immedate mode
    6.70 +	// interface.
    6.71 +	Vector4 cur_val[NUM_MESH_ATTR];
    6.72 +
    6.73 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
    6.74 +
    6.75 +	// vertex attribute data and buffer objects
    6.76 +	struct {
    6.77 +		int nelem;					// number of elements per attribute range: [1, 4]
    6.78 +		std::vector<float> data;
    6.79 +		unsigned int vbo;
    6.80 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
    6.81 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
    6.82 +		//int sdr_loc;
    6.83 +	} vattr[NUM_MESH_ATTR];
    6.84 +
    6.85 +	static int global_sdr_loc[NUM_MESH_ATTR];
    6.86 +
    6.87 +	std::vector<XFormNode*> bones;	// bones affecting this mesh
    6.88 +
    6.89 +	// index data and buffer object
    6.90 +	std::vector<unsigned int> idata;
    6.91 +	unsigned int ibo;
    6.92 +	mutable bool ibo_valid;
    6.93 +	mutable bool idata_valid;
    6.94 +
    6.95 +	// index buffer object for wireframe rendering (constructed on demand)
    6.96 +	unsigned int wire_ibo;
    6.97 +	mutable bool wire_ibo_valid;
    6.98 +
    6.99 +	// axis-aligned bounding box
   6.100 +	/*mutable AABox aabb;
   6.101 +	mutable bool aabb_valid;
   6.102 +
   6.103 +	// bounding sphere
   6.104 +	mutable Sphere bsph;
   6.105 +	mutable bool bsph_valid;*/
   6.106 +
   6.107 +	// keeps the last intersected face
   6.108 +	mutable Triangle hitface;
   6.109 +	// keeps the last intersected vertex position
   6.110 +	mutable Vector3 hitvert;
   6.111 +
   6.112 +	void calc_aabb();
   6.113 +	void calc_bsph();
   6.114 +
   6.115 +	static unsigned int intersect_mode;
   6.116 +	static float vertex_sel_dist;
   6.117 +
   6.118 +	static float vis_vecsize;
   6.119 +
   6.120 +	/// update the VBOs after data has changed (invalid vbo/ibo)
   6.121 +	void update_buffers();
   6.122 +	/// construct/update the wireframe index buffer (called from draw_wire).
   6.123 +	void update_wire_ibo();
   6.124 +
   6.125 +
   6.126 +public:
   6.127 +	Mesh();
   6.128 +	~Mesh();
   6.129 +
   6.130 +	void set_name(const char *name);
   6.131 +	const char *get_name() const;
   6.132 +
   6.133 +	bool has_attrib(int attr) const;
   6.134 +
   6.135 +	// clears everything about this mesh, and returns to the newly constructed state
   6.136 +	void clear();
   6.137 +
   6.138 +	// access the vertex attribute data
   6.139 +	// if vdata == 0, space is just allocated
   6.140 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
   6.141 +	float *get_attrib_data(int attrib);	// invalidates vbo
   6.142 +	const float *get_attrib_data(int attrib) const;
   6.143 +
   6.144 +	// simple access to any particular attribute
   6.145 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
   6.146 +	Vector4 get_attrib(int attrib, int idx) const;
   6.147 +
   6.148 +	// ... same for index data
   6.149 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
   6.150 +	unsigned int *get_index_data();	// invalidates ibo
   6.151 +	const unsigned int *get_index_data() const;
   6.152 +
   6.153 +	void append(const Mesh &mesh);
   6.154 +
   6.155 +	// immediate-mode style mesh construction interface
   6.156 +	void vertex(float x, float y, float z);
   6.157 +	void normal(float nx, float ny, float nz);
   6.158 +	void tangent(float tx, float ty, float tz);
   6.159 +	void texcoord(float u, float v, float w);
   6.160 +	void boneweights(float w1, float w2, float w3, float w4);
   6.161 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
   6.162 +
   6.163 +	/* apply a transformation to the vertices and its inverse-transpose
   6.164 +	 * to the normals and tangents.
   6.165 +	 */
   6.166 +	void apply_xform(const Matrix4x4 &xform);
   6.167 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
   6.168 +
   6.169 +	// adds a bone and returns its index
   6.170 +	int add_bone(XFormNode *bone);
   6.171 +	const XFormNode *get_bone(int idx) const;
   6.172 +	int get_bones_count() const;
   6.173 +
   6.174 +	// access the shader attribute locations
   6.175 +	static void set_attrib_location(int attr, int loc);
   6.176 +	static int get_attrib_location(int attr);
   6.177 +	static void clear_attrib_locations();
   6.178 +
   6.179 +	static void set_vis_vecsize(float sz);
   6.180 +	static float get_vis_vecsize();
   6.181 +
   6.182 +	void draw() const;
   6.183 +	void draw_wire() const;
   6.184 +	void draw_vertices() const;
   6.185 +	void draw_normals() const;
   6.186 +	void draw_tangents() const;
   6.187 +
   6.188 +#if 0
   6.189 +	/** get the bounding box in local space. The result will be cached, and subsequent
   6.190 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
   6.191 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
   6.192 +	 * @{ */
   6.193 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
   6.194 +	const AABox &get_aabbox() const;
   6.195 +	/// @}
   6.196 +
   6.197 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
   6.198 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
   6.199 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
   6.200 +	 * @{ */
   6.201 +	float get_bsphere(Vector3 *center, float *rad) const;
   6.202 +	const Sphere &get_bsphere() const;
   6.203 +
   6.204 +	static void set_intersect_mode(unsigned int mode);
   6.205 +	static unsigned int get_intersect_mode();
   6.206 +	static void set_vertex_select_distance(float dist);
   6.207 +	static float get_vertex_select_distance();
   6.208 +
   6.209 +	/** Find the intersection between the mesh and a ray.
   6.210 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
   6.211 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
   6.212 +	 */
   6.213 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   6.214 +#endif
   6.215 +};
   6.216 +
   6.217 +
   6.218  #endif	// MESH_H_
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/opengl.cc	Sat Aug 17 23:51:24 2013 +0300
     7.3 @@ -0,0 +1,29 @@
     7.4 +#include "opengl.h"
     7.5 +
     7.6 +void init_opengl()
     7.7 +{
     7.8 +#ifdef __GLEW_H__
     7.9 +	glewInit();
    7.10 +#endif
    7.11 +}
    7.12 +
    7.13 +const char *strglerr(int err)
    7.14 +{
    7.15 +	static const char *errnames[] = {
    7.16 +		"GL_INVALID_ENUM",
    7.17 +		"GL_INVALID_VALUE",
    7.18 +		"GL_INVALID_OPERATION",
    7.19 +		"GL_STACK_OVERFLOW",
    7.20 +		"GL_STACK_UNDERFLOW",
    7.21 +		"GL_OUT_OF_MEMORY",
    7.22 +		"GL_INVALID_FRAMEBUFFER_OPERATION"
    7.23 +	};
    7.24 +
    7.25 +	if(!err) {
    7.26 +		return "GL_NO_ERROR";
    7.27 +	}
    7.28 +	if(err < GL_INVALID_ENUM || err > GL_OUT_OF_MEMORY) {
    7.29 +		return "<invalid gl error>";
    7.30 +	}
    7.31 +	return errnames[err - GL_INVALID_ENUM];
    7.32 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/opengl.h	Sat Aug 17 23:51:24 2013 +0300
     8.3 @@ -0,0 +1,71 @@
     8.4 +#ifndef OPENGL_H_
     8.5 +#define OPENGL_H_
     8.6 +
     8.7 +#include <stdlib.h>
     8.8 +
     8.9 +#ifdef __APPLE__
    8.10 +#include "TargetConditionals.h"
    8.11 +
    8.12 +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
    8.13 +/* iOS */
    8.14 +#include <OpenGLES/ES2/gl.h>
    8.15 +#include <OpenGLES/ES2/glext.h>
    8.16 +
    8.17 +#define GL_CLAMP			GL_CLAMP_TO_EDGE
    8.18 +#define GL_DEPTH24_STENCIL8	GL_DEPTH24_STENCIL8_OES
    8.19 +
    8.20 +#undef USE_OLDGL
    8.21 +
    8.22 +#define GL_WRITE_ONLY	GL_WRITE_ONLY_OES
    8.23 +#define glMapBuffer		glMapBufferOES
    8.24 +#define glUnmapBuffer	glUnmapBufferOES
    8.25 +
    8.26 +#else
    8.27 +/* MacOS X */
    8.28 +#include <GL/glew.h>
    8.29 +#include <GLUT/glut.h>
    8.30 +
    8.31 +#define USE_OLDGL
    8.32 +#endif
    8.33 +
    8.34 +#else
    8.35 +/* UNIX or Windows */
    8.36 +#include <GL/glew.h>
    8.37 +#include <GL/glut.h>
    8.38 +
    8.39 +#define USE_OLDGL
    8.40 +#endif
    8.41 +
    8.42 +#ifndef GL_RGB16F
    8.43 +#define GL_RGB16F	0x881b
    8.44 +#endif
    8.45 +#ifndef GL_RGBA16F
    8.46 +#define GL_RGBA16F	0x881a
    8.47 +#endif
    8.48 +#ifndef GL_RGB32F
    8.49 +#define GL_RGB32F	0x8815
    8.50 +#endif
    8.51 +#ifndef GL_RGBA32F
    8.52 +#define GL_RGBA32F	0x8814
    8.53 +#endif
    8.54 +#ifndef GL_LUMINANCE16F
    8.55 +#define GL_LUMINANCE16F	0x881e
    8.56 +#endif
    8.57 +#ifndef GL_LUMINANCE32F
    8.58 +#define GL_LUMINANCE32F	0x8818
    8.59 +#endif
    8.60 +
    8.61 +#define CHECKGLERR	\
    8.62 +	do { \
    8.63 +		int err = glGetError(); \
    8.64 +		if(err) { \
    8.65 +			fprintf(stderr, "%s:%d: OpenGL error 0x%x: %s\n", __FILE__, __LINE__, err, strglerr(err)); \
    8.66 +			abort(); \
    8.67 +		} \
    8.68 +	} while(0)
    8.69 +
    8.70 +void init_opengl();
    8.71 +
    8.72 +const char *strglerr(int err);
    8.73 +
    8.74 +#endif	// OPENGL_H_
     9.1 --- a/src/vmath.h	Sat Aug 17 16:10:26 2013 +0300
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,29 +0,0 @@
     9.4 -#ifndef VMATH_H_
     9.5 -#define VMATH_H_
     9.6 -
     9.7 -class Vector3 {
     9.8 -public:
     9.9 -	float x, y, z;
    9.10 -
    9.11 -	Vector3() : x(0), y(0), z(0) {}
    9.12 -	Vector3(float x, float y, float z) {
    9.13 -		this->x = x;
    9.14 -		this->y = y;
    9.15 -		this->z = z;
    9.16 -	}
    9.17 -};
    9.18 -
    9.19 -class Vector4 {
    9.20 -public:
    9.21 -	float x, y, z, w;
    9.22 -
    9.23 -	Vector4() : x(0), y(0), z(0), w(1) {}
    9.24 -	Vector4(float x, float y, float z, float w) {
    9.25 -		this->x = x;
    9.26 -		this->y = y;
    9.27 -		this->z = z;
    9.28 -		this->w = w;
    9.29 -	}
    9.30 -};
    9.31 -
    9.32 -#endif	// VMATH_H_
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/xform_node.cc	Sat Aug 17 23:51:24 2013 +0300
    10.3 @@ -0,0 +1,370 @@
    10.4 +#include <assert.h>
    10.5 +#include <algorithm>
    10.6 +#include "xform_node.h"
    10.7 +#include "anim/anim.h"
    10.8 +#include "anim/track.h"
    10.9 +
   10.10 +static inline anm_interpolator track_interpolator(Interp in);
   10.11 +static inline anm_extrapolator track_extrapolator(Extrap ex);
   10.12 +
   10.13 +XFormNode::XFormNode()
   10.14 +{
   10.15 +	anm = new anm_node;
   10.16 +	anm_init_node(anm);
   10.17 +}
   10.18 +
   10.19 +XFormNode::~XFormNode()
   10.20 +{
   10.21 +	anm_destroy_node(anm);
   10.22 +	delete anm;
   10.23 +}
   10.24 +
   10.25 +void XFormNode::set_name(const char *name)
   10.26 +{
   10.27 +	anm_set_node_name(anm, name);
   10.28 +}
   10.29 +
   10.30 +const char *XFormNode::get_name() const
   10.31 +{
   10.32 +	return anm_get_node_name(anm);
   10.33 +}
   10.34 +
   10.35 +void XFormNode::set_interpolator(Interp in)
   10.36 +{
   10.37 +	anm_set_interpolator(anm, track_interpolator(in));
   10.38 +	interp = in;
   10.39 +}
   10.40 +
   10.41 +Interp XFormNode::get_interpolator() const
   10.42 +{
   10.43 +	return interp;
   10.44 +}
   10.45 +
   10.46 +void XFormNode::set_extrapolator(Extrap ex)
   10.47 +{
   10.48 +	anm_set_extrapolator(anm, track_extrapolator(ex));
   10.49 +	extrap = ex;
   10.50 +}
   10.51 +
   10.52 +Extrap XFormNode::get_extrapolator() const
   10.53 +{
   10.54 +	return extrap;
   10.55 +}
   10.56 +
   10.57 +void XFormNode::add_child(XFormNode *child)
   10.58 +{
   10.59 +	children.push_back(child);
   10.60 +	anm_link_node(anm, child->anm);
   10.61 +}
   10.62 +
   10.63 +void XFormNode::remove_child(XFormNode *child)
   10.64 +{
   10.65 +	std::vector<XFormNode*>::iterator it;
   10.66 +	it = std::find(children.begin(), children.end(), child);
   10.67 +	if(it != children.end()) {
   10.68 +		children.erase(it);
   10.69 +		anm_unlink_node(anm, child->anm);
   10.70 +	}
   10.71 +}
   10.72 +
   10.73 +int XFormNode::get_children_count() const
   10.74 +{
   10.75 +	return (int)children.size();
   10.76 +}
   10.77 +
   10.78 +XFormNode *XFormNode::get_child(int idx)
   10.79 +{
   10.80 +	if(idx >= 0 && idx < get_children_count()) {
   10.81 +		return children[idx];
   10.82 +	}
   10.83 +	return 0;
   10.84 +}
   10.85 +
   10.86 +const XFormNode *XFormNode::get_child(int idx) const
   10.87 +{
   10.88 +	if(idx >= 0 && idx < get_children_count()) {
   10.89 +		return children[idx];
   10.90 +	}
   10.91 +	return 0;
   10.92 +}
   10.93 +
   10.94 +void XFormNode::set_position(const Vector3 &pos, long tmsec)
   10.95 +{
   10.96 +	anm_set_position(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
   10.97 +}
   10.98 +
   10.99 +Vector3 XFormNode::get_node_position(long tmsec) const
  10.100 +{
  10.101 +	vec3_t p = anm_get_node_position(anm, ANM_MSEC2TM(tmsec));
  10.102 +	return Vector3(p.x, p.y, p.z);
  10.103 +}
  10.104 +
  10.105 +void XFormNode::set_rotation(const Quaternion &quat, long tmsec)
  10.106 +{
  10.107 +	anm_set_rotation(anm, quat_cons(quat.s, quat.v.x, quat.v.y, quat.v.z), ANM_MSEC2TM(tmsec));
  10.108 +}
  10.109 +
  10.110 +Quaternion XFormNode::get_node_rotation(long tmsec) const
  10.111 +{
  10.112 +	quat_t q = anm_get_node_rotation(anm, ANM_MSEC2TM(tmsec));
  10.113 +	return Quaternion(q.w, q.x, q.y, q.z);
  10.114 +}
  10.115 +
  10.116 +void XFormNode::set_scaling(const Vector3 &pos, long tmsec)
  10.117 +{
  10.118 +	anm_set_scaling(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
  10.119 +}
  10.120 +
  10.121 +Vector3 XFormNode::get_node_scaling(long tmsec) const
  10.122 +{
  10.123 +	vec3_t s = anm_get_node_scaling(anm, ANM_MSEC2TM(tmsec));
  10.124 +	return Vector3(s.x, s.y, s.z);
  10.125 +}
  10.126 +
  10.127 +// these take hierarchy into account
  10.128 +Vector3 XFormNode::get_position(long tmsec) const
  10.129 +{
  10.130 +	vec3_t v = anm_get_position(anm, ANM_MSEC2TM(tmsec));
  10.131 +	return Vector3(v.x, v.y, v.z);
  10.132 +}
  10.133 +
  10.134 +Quaternion XFormNode::get_rotation(long tmsec) const
  10.135 +{
  10.136 +	quat_t q = anm_get_rotation(anm, tmsec);
  10.137 +	return Quaternion(q.w, q.x, q.y, q.z);
  10.138 +}
  10.139 +
  10.140 +Vector3 XFormNode::get_scaling(long tmsec) const
  10.141 +{
  10.142 +	vec3_t v = anm_get_scaling(anm, ANM_MSEC2TM(tmsec));
  10.143 +	return Vector3(v.x, v.y, v.z);
  10.144 +}
  10.145 +
  10.146 +void XFormNode::set_pivot(const Vector3 &pivot)
  10.147 +{
  10.148 +	anm_set_pivot(anm, v3_cons(pivot.x, pivot.y, pivot.z));
  10.149 +}
  10.150 +
  10.151 +Vector3 XFormNode::get_pivot() const
  10.152 +{
  10.153 +	vec3_t p = anm_get_pivot(anm);
  10.154 +	return Vector3(p.x, p.y, p.z);
  10.155 +}
  10.156 +
  10.157 +void XFormNode::set_local_matrix(const Matrix4x4 &mat)
  10.158 +{
  10.159 +	local_matrix = mat;
  10.160 +}
  10.161 +
  10.162 +const Matrix4x4 &XFormNode::get_local_matrix() const
  10.163 +{
  10.164 +	return local_matrix;
  10.165 +}
  10.166 +
  10.167 +void XFormNode::set_bone_matrix(const Matrix4x4 &bmat)
  10.168 +{
  10.169 +	bone_matrix = bmat;
  10.170 +}
  10.171 +
  10.172 +const Matrix4x4 &XFormNode::get_bone_matrix() const
  10.173 +{
  10.174 +	return bone_matrix;
  10.175 +}
  10.176 +
  10.177 +#define FOO
  10.178 +
  10.179 +void XFormNode::get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  10.180 +{
  10.181 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  10.182 +
  10.183 +	if(mat) {
  10.184 +		anm_get_node_matrix(anm, (scalar_t(*)[4])mat, tm);
  10.185 +#ifdef FOO
  10.186 +		*mat = local_matrix * *mat;
  10.187 +#else
  10.188 +		*mat = *mat * local_matrix;
  10.189 +#endif
  10.190 +	}
  10.191 +	if(inv_mat) {
  10.192 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  10.193 +	}
  10.194 +}
  10.195 +
  10.196 +void XFormNode::get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  10.197 +{
  10.198 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  10.199 +
  10.200 +	if(mat) {
  10.201 +		anm_get_matrix(anm, (scalar_t(*)[4])mat, tm);
  10.202 +#ifdef FOO
  10.203 +		*mat = local_matrix * *mat;
  10.204 +#else
  10.205 +		*mat = *mat * local_matrix;
  10.206 +#endif
  10.207 +	}
  10.208 +	if(inv_mat) {
  10.209 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  10.210 +	}
  10.211 +}
  10.212 +
  10.213 +
  10.214 +// ---- Track ----
  10.215 +
  10.216 +Track::Track()
  10.217 +{
  10.218 +	trk = new anm_track;
  10.219 +	anm_init_track(trk);
  10.220 +}
  10.221 +
  10.222 +Track::~Track()
  10.223 +{
  10.224 +	anm_destroy_track(trk);
  10.225 +	delete trk;
  10.226 +}
  10.227 +
  10.228 +Track::Track(const Track &rhs)
  10.229 +{
  10.230 +	trk = new anm_track;
  10.231 +	anm_init_track(trk);
  10.232 +	anm_copy_track(trk, rhs.trk);
  10.233 +	interp = rhs.interp;
  10.234 +	extrap = rhs.extrap;
  10.235 +}
  10.236 +
  10.237 +Track &Track::operator =(const Track &rhs)
  10.238 +{
  10.239 +	if(&rhs == this) {
  10.240 +		return *this;
  10.241 +	}
  10.242 +
  10.243 +	anm_copy_track(trk, rhs.trk);
  10.244 +	interp = rhs.interp;
  10.245 +	extrap = rhs.extrap;
  10.246 +	return *this;
  10.247 +}
  10.248 +
  10.249 +
  10.250 +void Track::set_interpolator(Interp in)
  10.251 +{
  10.252 +	anm_set_track_interpolator(trk, track_interpolator(in));
  10.253 +	interp = in;
  10.254 +}
  10.255 +
  10.256 +Interp Track::get_interpolator() const
  10.257 +{
  10.258 +	return interp;
  10.259 +}
  10.260 +
  10.261 +void Track::set_extrapolator(Extrap ex)
  10.262 +{
  10.263 +	anm_set_track_extrapolator(trk, track_extrapolator(ex));
  10.264 +	extrap = ex;
  10.265 +}
  10.266 +
  10.267 +Extrap Track::get_extrapolator() const
  10.268 +{
  10.269 +	return extrap;
  10.270 +}
  10.271 +
  10.272 +void Track::set_default(double def)
  10.273 +{
  10.274 +	anm_set_track_default(trk, def);
  10.275 +}
  10.276 +
  10.277 +void Track::set_value(float val, long tmsec)
  10.278 +{
  10.279 +	anm_set_value(trk, ANM_MSEC2TM(tmsec), val);
  10.280 +}
  10.281 +
  10.282 +float Track::get_value(long tmsec) const
  10.283 +{
  10.284 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  10.285 +}
  10.286 +
  10.287 +float Track::operator ()(long tmsec) const
  10.288 +{
  10.289 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  10.290 +}
  10.291 +
  10.292 +
  10.293 +// ---- Track3 ----
  10.294 +
  10.295 +void Track3::set_interpolator(Interp in)
  10.296 +{
  10.297 +	for(int i=0; i<3; i++) {
  10.298 +		track[i].set_interpolator(in);
  10.299 +	}
  10.300 +}
  10.301 +
  10.302 +Interp Track3::get_interpolator() const
  10.303 +{
  10.304 +	return track[0].get_interpolator();
  10.305 +}
  10.306 +
  10.307 +void Track3::set_extrapolator(Extrap ex)
  10.308 +{
  10.309 +	for(int i=0; i<3; i++) {
  10.310 +		track[i].set_extrapolator(ex);
  10.311 +	}
  10.312 +}
  10.313 +
  10.314 +Extrap Track3::get_extrapolator() const
  10.315 +{
  10.316 +	return track[0].get_extrapolator();
  10.317 +}
  10.318 +
  10.319 +void Track3::set_default(const Vector3 &def)
  10.320 +{
  10.321 +	for(int i=0; i<3; i++) {
  10.322 +		track[i].set_default(def[i]);
  10.323 +	}
  10.324 +}
  10.325 +
  10.326 +void Track3::set_value(const Vector3 &val, long tmsec)
  10.327 +{
  10.328 +	for(int i=0; i<3; i++) {
  10.329 +		track[i].set_value(val[i], tmsec);
  10.330 +	}
  10.331 +}
  10.332 +
  10.333 +Vector3 Track3::get_value(long tmsec) const
  10.334 +{
  10.335 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  10.336 +}
  10.337 +
  10.338 +Vector3 Track3::operator ()(long tmsec) const
  10.339 +{
  10.340 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  10.341 +}
  10.342 +
  10.343 +
  10.344 +static inline anm_interpolator track_interpolator(Interp in)
  10.345 +{
  10.346 +	switch(in) {
  10.347 +	case INTERP_STEP:
  10.348 +		return ANM_INTERP_STEP;
  10.349 +	case INTERP_LINEAR:
  10.350 +		return ANM_INTERP_LINEAR;
  10.351 +	case INTERP_CUBIC:
  10.352 +		return ANM_INTERP_CUBIC;
  10.353 +	}
  10.354 +
  10.355 +	assert(0);
  10.356 +	return ANM_INTERP_STEP;
  10.357 +}
  10.358 +
  10.359 +static inline anm_extrapolator track_extrapolator(Extrap ex)
  10.360 +{
  10.361 +	switch(ex) {
  10.362 +	case EXTRAP_EXTEND:
  10.363 +		return ANM_EXTRAP_EXTEND;
  10.364 +	case EXTRAP_CLAMP:
  10.365 +		return ANM_EXTRAP_CLAMP;
  10.366 +	case EXTRAP_REPEAT:
  10.367 +		return ANM_EXTRAP_REPEAT;
  10.368 +	}
  10.369 +
  10.370 +	assert(0);
  10.371 +	return ANM_EXTRAP_EXTEND;
  10.372 +}
  10.373 +
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/xform_node.h	Sat Aug 17 23:51:24 2013 +0300
    11.3 @@ -0,0 +1,134 @@
    11.4 +/*
    11.5 +TODO: add multiple animations per node in libanim (i.e. multiple sets of tracks)
    11.6 +*/
    11.7 +#ifndef XFORM_NODE_H_
    11.8 +#define XFORM_NODE_H_
    11.9 +
   11.10 +#include <vector>
   11.11 +#include "vmath/vector.h"
   11.12 +#include "vmath/quat.h"
   11.13 +#include "vmath/matrix.h"
   11.14 +
   11.15 +enum Interp { INTERP_STEP, INTERP_LINEAR, INTERP_CUBIC };
   11.16 +enum Extrap { EXTRAP_EXTEND, EXTRAP_CLAMP, EXTRAP_REPEAT };
   11.17 +
   11.18 +struct anm_node;
   11.19 +struct anm_track;
   11.20 +
   11.21 +// XXX all time arguments are milliseconds
   11.22 +
   11.23 +class XFormNode {
   11.24 +private:
   11.25 +	struct anm_node *anm;
   11.26 +	std::vector<XFormNode*> children;
   11.27 +
   11.28 +	Interp interp;
   11.29 +	Extrap extrap;
   11.30 +
   11.31 +	Matrix4x4 local_matrix;
   11.32 +	Matrix4x4 bone_matrix;
   11.33 +
   11.34 +	XFormNode(const XFormNode &node) {}
   11.35 +	XFormNode &operator =(const XFormNode &node) { return *this; }
   11.36 +
   11.37 +public:
   11.38 +	XFormNode();
   11.39 +	virtual ~XFormNode();
   11.40 +
   11.41 +	void set_name(const char *name);
   11.42 +	const char *get_name() const;
   11.43 +
   11.44 +	void set_interpolator(Interp in);
   11.45 +	Interp get_interpolator() const;
   11.46 +	void set_extrapolator(Extrap ex);
   11.47 +	Extrap get_extrapolator() const;
   11.48 +
   11.49 +	// children management
   11.50 +	void add_child(XFormNode *child);
   11.51 +	void remove_child(XFormNode *child);
   11.52 +
   11.53 +	int get_children_count() const;
   11.54 +	XFormNode *get_child(int idx);
   11.55 +	const XFormNode *get_child(int idx) const;
   11.56 +
   11.57 +
   11.58 +	void set_position(const Vector3 &pos, long tmsec = 0);
   11.59 +	Vector3 get_node_position(long tmsec = 0) const;
   11.60 +
   11.61 +	void set_rotation(const Quaternion &quat, long tmsec = 0);
   11.62 +	Quaternion get_node_rotation(long tmsec = 0) const;
   11.63 +
   11.64 +	void set_scaling(const Vector3 &pos, long tmsec = 0);
   11.65 +	Vector3 get_node_scaling(long tmsec = 0) const;
   11.66 +
   11.67 +	// these take hierarchy into account
   11.68 +	Vector3 get_position(long tmsec = 0) const;
   11.69 +	Quaternion get_rotation(long tmsec = 0) const;
   11.70 +	Vector3 get_scaling(long tmsec = 0) const;
   11.71 +
   11.72 +	void set_pivot(const Vector3 &pivot);
   11.73 +	Vector3 get_pivot() const;
   11.74 +
   11.75 +	// the local matrix is concatenated with the regular node/anim matrix
   11.76 +	void set_local_matrix(const Matrix4x4 &mat);
   11.77 +	const Matrix4x4 &get_local_matrix() const;
   11.78 +
   11.79 +	// for bone nodes, the transformation of the bone in bind position
   11.80 +	void set_bone_matrix(const Matrix4x4 &bmat);
   11.81 +	const Matrix4x4 &get_bone_matrix() const;
   11.82 +
   11.83 +	// node transformation alone
   11.84 +	void get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
   11.85 +
   11.86 +	// node transformation taking hierarchy into account
   11.87 +	void get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
   11.88 +};
   11.89 +
   11.90 +
   11.91 +class Track {
   11.92 +private:
   11.93 +	struct anm_track *trk;
   11.94 +	Interp interp;
   11.95 +	Extrap extrap;
   11.96 +
   11.97 +public:
   11.98 +	Track();
   11.99 +	~Track();
  11.100 +
  11.101 +	Track(const Track &trk);
  11.102 +	Track &operator =(const Track &trk);
  11.103 +
  11.104 +	void set_interpolator(Interp in);
  11.105 +	Interp get_interpolator() const;
  11.106 +	void set_extrapolator(Extrap ex);
  11.107 +	Extrap get_extrapolator() const;
  11.108 +
  11.109 +	void set_default(double def);
  11.110 +
  11.111 +	void set_value(float val, long tmsec = 0);
  11.112 +	float get_value(long tmsec = 0) const;
  11.113 +
  11.114 +	// the same as get_value
  11.115 +	float operator ()(long tmsec = 0) const;
  11.116 +};
  11.117 +
  11.118 +class Track3 {
  11.119 +private:
  11.120 +	Track track[3];
  11.121 +
  11.122 +public:
  11.123 +	void set_interpolator(Interp in);
  11.124 +	Interp get_interpolator() const;
  11.125 +	void set_extrapolator(Extrap ex);
  11.126 +	Extrap get_extrapolator() const;
  11.127 +
  11.128 +	void set_default(const Vector3 &def);
  11.129 +
  11.130 +	void set_value(const Vector3 &val, long tmsec = 0);
  11.131 +	Vector3 get_value(long tmsec = 0) const;
  11.132 +
  11.133 +	// the same as get_value
  11.134 +	Vector3 operator ()(long tmsec = 0) const;
  11.135 +};
  11.136 +
  11.137 +#endif	/* XFORM_NODE_H_ */