# HG changeset patch # User John Tsiombikas # Date 1376772684 -10800 # Node ID e46529a5d0570574cc8fa83d7e43aad8e90f6cdf # Parent 2918358f5e6dda0f30601b4e4ba86de16501ebd3 some progress diff -r 2918358f5e6d -r e46529a5d057 Makefile --- a/Makefile Sat Aug 17 16:10:26 2013 +0300 +++ b/Makefile Sat Aug 17 23:51:24 2013 +0300 @@ -27,6 +27,7 @@ endif CXXFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic) +LDFLAGS = -lvmath -lanim .PHONY: all all: $(lib_so) $(lib_a) diff -r 2918358f5e6d -r e46529a5d057 src/chunk.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/chunk.h Sat Aug 17 23:51:24 2013 +0300 @@ -0,0 +1,64 @@ +#ifndef CHUNK_H_ +#define CHUNK_H_ + +enum { + CNK_INVALID, // this shouldn't appear in files + CNK_SCENE, // the root chunk + + // general purpose chunks + CNK_INT, + CNK_UINT, + CNK_FLOAT, + CNK_VEC3, + CNK_VEC4, + CNK_STRING, + + // --- first level chunks --- + // children of CNK_SCENE + CNK_ENV, // environmental parameters + CNK_MTL_LIST, // material library + CNK_MESH_LIST, // all the meshes hang under this chunk + CNK_LIGHT_LIST, // likewise for lights + CNK_CAMERA_LIST, // likewise for cameras + CNK_NODE_LIST, // likewise for nodes + CNK_ANIM_LIST, // all animations + + // --- second level chunks --- + // children of CNK_ENV + CNK_ENV_AMBIENT, // ambient color, contains a single CNK_VEC3 + CNK_ENV_FOG, + + // children of CNK_*_LIST + CNK_MTL, + CNK_MESH, + CNK_LIGHT, + CNK_CAMERA, + CNK_NODE, + + // --- third level chunks --- + // children of CNK_FOG + CNK_FOG_COLOR, // fog color, contains a single CNK_VEC3 + CNK_FOG_EXP, // fog exponent, contains a single CNK_REAL + + // children of CNK_MTL + CNK_MTL_ATTR, // material attribute, has a CNK_STRING for its name, + // a CNK_MTL_ATTR_VAL, and optionally a CNK_MTL_ATTR_MAP + // children of CNK_MTL_ATTR + CNK_MTL_ATTR_VAL, // can have a single CNK_FLOAT, CNK_VEC3, or CNK_VEC4 + CNK_MTL_ATTR_MAP, // has a single CNK_STRING + + // children of CNK_MESH + // TODO... +}; + +struct ChunkHeader { + uint32_t id; + uint32_t size; +}; + +struct Chunk { + ChunkHeader hdr; + char data[1]; +}; + +#endif // CHUNK_H_ diff -r 2918358f5e6d -r e46529a5d057 src/goat3d_impl.h --- a/src/goat3d_impl.h Sat Aug 17 16:10:26 2013 +0300 +++ b/src/goat3d_impl.h Sat Aug 17 23:51:24 2013 +0300 @@ -2,8 +2,8 @@ #define GOAT3D_IMPL_H_ #include +#include #include "goat3d.h" -#include "vmath.h" #include "mesh.h" #include "light.h" #include "camera.h" diff -r 2918358f5e6d -r e46529a5d057 src/material.h --- a/src/material.h Sat Aug 17 16:10:26 2013 +0300 +++ b/src/material.h Sat Aug 17 23:51:24 2013 +0300 @@ -1,8 +1,44 @@ #ifndef MATERIAL_H_ #define MATERIAL_H_ +#include +#include +#include + +struct MaterialAttrib { + Vector4 value; + std::string map; +}; + +#define MAT_ATTR_DIFFUSE "diffuse" +#define MAT_ATTR_SPECULAR "specular" +#define MAT_ATTR_SHININESS "shininess" +#define MAT_ATTR_NORMAL "normal" +#define MAT_ATTR_BUMP "bump" +#define MAT_ATTR_REFLECTION "reflection" +#define MAT_ATTR_TRANSMISSION "transmission" +#define MAT_ATTR_IOR "ior" + class Material { - // TODO +private: + static MaterialAttrib def_attr; + + std::map attrib; + +public: + MaterialAttrib &operator [](const std::string &name) + { + return attrib[name]; + } + + const MaterialAttrib &operator [](const std::string &name) const + { + std::map::const_iterator it; + if((it = attrib.find(name)) != attrib.end()) { + return it->second; + } + return def_attr; + } }; #endif // MATERIAL_H_ diff -r 2918358f5e6d -r e46529a5d057 src/mesh.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mesh.cc Sat Aug 17 23:51:24 2013 +0300 @@ -0,0 +1,973 @@ +#include +#include +#include +#include +#include "opengl.h" +#include "mesh.h" +#include "xform_node.h" +//#include "logger.h" + +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 }; +unsigned int Mesh::intersect_mode = ISECT_DEFAULT; +float Mesh::vertex_sel_dist = 0.01; +float Mesh::vis_vecsize = 1.0; + +Mesh::Mesh() +{ + clear(); + + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); + + for(int i=0; iname = name; +} + +const char *Mesh::get_name() const +{ + return name.c_str(); +} + +bool Mesh::has_attrib(int attr) const +{ + if(attr < 0 || attr >= NUM_MESH_ATTR) { + return false; + } + + // if neither of these is valid, then nobody has set this attribute + return vattr[attr].vbo_valid || vattr[attr].data_valid; +} + +void Mesh::clear() +{ + bones.clear(); + + for(int i=0; i= NUM_MESH_ATTR) { + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + if(nverts && num != nverts) { + fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts); + return 0; + } + nverts = num; + + vattr[attrib].data.clear(); + vattr[attrib].nelem = nelem; + vattr[attrib].data.resize(num * nelem); + + if(data) { + memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data); + } + + vattr[attrib].data_valid = true; + vattr[attrib].vbo_valid = false; + return &vattr[attrib].data[0]; +} + +float *Mesh::get_attrib_data(int attrib) +{ + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + vattr[attrib].vbo_valid = false; + return (float*)((const Mesh*)this)->get_attrib_data(attrib); +} + +const float *Mesh::get_attrib_data(int attrib) const +{ + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + if(!vattr[attrib].data_valid) { +#if GL_ES_VERSION_2_0 + fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__); + return 0; +#else + if(!vattr[attrib].vbo_valid) { + fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + // local data copy is unavailable, grab the data from the vbo + Mesh *m = (Mesh*)this; + m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem); + + glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo); + void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); + memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float)); + glUnmapBuffer(GL_ARRAY_BUFFER); + + vattr[attrib].data_valid = true; +#endif + } + + return &vattr[attrib].data[0]; +} + +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v) +{ + float *data = get_attrib_data(attrib); + if(data) { + data += idx * vattr[attrib].nelem; + for(int i=0; iget_index_data(); +} + +const unsigned int *Mesh::get_index_data() const +{ + if(!idata_valid) { +#if GL_ES_VERSION_2_0 + fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__); + return 0; +#else + if(!ibo_valid) { + fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__); + return 0; + } + + // local data copy is unavailable, gram the data from the ibo + Mesh *m = (Mesh*)this; + int nidx = nfaces * 3; + m->idata.resize(nidx); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); + memcpy(&m->idata[0], data, nidx * sizeof(unsigned int)); + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + + idata_valid = true; +#endif + } + + return &idata[0]; +} + +void Mesh::append(const Mesh &mesh) +{ + unsigned int idxoffs = nverts; + + nverts += mesh.nverts; + nfaces += mesh.nfaces; + + for(int i=0; i= NUM_MESH_ATTR) { + return; + } + Mesh::global_sdr_loc[attr] = loc; +} + +/// static function +int Mesh::get_attrib_location(int attr) +{ + if(attr < 0 || attr >= NUM_MESH_ATTR) { + return -1; + } + return Mesh::global_sdr_loc[attr]; +} + +/// static function +void Mesh::clear_attrib_locations() +{ + for(int i=0; i= (int)bones.size()) { + return 0; + } + return bones[idx]; +} + +int Mesh::get_bones_count() const +{ + return (int)bones.size(); +} + +void Mesh::draw() const +{ + ((Mesh*)this)->update_buffers(); + + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); + return; + } + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); + return; + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(loc); + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if(ibo_valid) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + glDrawArrays(GL_TRIANGLES, 0, nverts); + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glDisableVertexAttribArray(loc); + } + } +} + +void Mesh::draw_wire() const +{ + ((Mesh*)this)->update_wire_ibo(); + + if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) { + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); + return; + } + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); + return; + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(loc); + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); + glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glDisableVertexAttribArray(loc); + } + } +} + +void Mesh::draw_vertices() const +{ + ((Mesh*)this)->update_buffers(); + + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); + return; + } + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); + return; + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(loc); + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDrawArrays(GL_POINTS, 0, nverts); + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glDisableVertexAttribArray(loc); + } + } +} + +void Mesh::draw_normals() const +{ +#ifdef USE_OLDGL + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; + Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); + Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); + + if(!varr || !norm || vert_loc < 0) { + return; + } + + glBegin(GL_LINES); + for(size_t i=0; icalc_aabb(); + } + *vmin = aabb.min; + *vmax = aabb.max; +} + +const AABox &Mesh::get_aabbox() const +{ + if(!aabb_valid) { + ((Mesh*)this)->calc_aabb(); + } + return aabb; +} + +float Mesh::get_bsphere(Vector3 *center, float *rad) const +{ + if(!bsph_valid) { + ((Mesh*)this)->calc_bsph(); + } + *center = bsph.center; + *rad = bsph.radius; + return bsph.radius; +} + +const Sphere &Mesh::get_bsphere() const +{ + if(!bsph_valid) { + ((Mesh*)this)->calc_bsph(); + } + return bsph; +} + +/// static function +void Mesh::set_intersect_mode(unsigned int mode) +{ + Mesh::intersect_mode = mode; +} + +/// static function +unsigned int Mesh::get_intersect_mode() +{ + return Mesh::intersect_mode; +} + +/// static function +void Mesh::set_vertex_select_distance(float dist) +{ + Mesh::vertex_sel_dist = dist; +} + +/// static function +float Mesh::get_vertex_select_distance() +{ + return Mesh::vertex_sel_dist; +} + +/*bool Mesh::intersect(const Ray &ray, HitPoint *hit) const +{ + assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE)); + + const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); + const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); + if(!varr) { + return false; + } + const unsigned int *idxarr = get_index_data(); + + // first test with the bounding box + AABox box; + get_aabbox(&box.min, &box.max); + if(!box.intersect(ray)) { + return false; + } + + HitPoint nearest_hit; + nearest_hit.dist = FLT_MAX; + nearest_hit.obj = 0; + + if(Mesh::intersect_mode & ISECT_VERTICES) { + // we asked for "intersections" with the vertices of the mesh + long nearest_vidx = -1; + float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist; + + for(unsigned int i=0; i 0) { + continue; + } + + // project the vertex onto the ray line + float t = dot_product(varr[i] - ray.origin, ray.dir); + Vector3 vproj = ray.origin + ray.dir * t; + + float dist_sq = (vproj - varr[i]).length_sq(); + if(dist_sq < thres_sq) { + if(!hit) { + return true; + } + if(t < nearest_hit.dist) { + nearest_hit.dist = t; + nearest_vidx = i; + } + } + } + + if(nearest_vidx != -1) { + hitvert = varr[nearest_vidx]; + nearest_hit.obj = &hitvert; + } + + } else { + // regular intersection test with polygons + + for(unsigned int i=0; i 0) { + continue; + } + + HitPoint fhit; + if(face.intersect(ray, hit ? &fhit : 0)) { + if(!hit) { + return true; + } + if(fhit.dist < nearest_hit.dist) { + nearest_hit = fhit; + hitface = face; + } + } + } + } + + if(nearest_hit.obj) { + if(hit) { + *hit = nearest_hit; + + // if we are interested in the mesh and not the faces set obj to this + if(Mesh::intersect_mode & ISECT_FACE) { + hit->obj = &hitface; + } else if(Mesh::intersect_mode & ISECT_VERTICES) { + hit->obj = &hitvert; + } else { + hit->obj = this; + } + } + return true; + } + return false; +}*/ + + +// ------ private member functions ------ + +void Mesh::calc_aabb() +{ + // the cast is to force calling the const version which doesn't invalidate + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { + return; + } + + aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX); + aabb.max = -aabb.min; + + for(unsigned int i=0; i aabb.max[j]) { + aabb.max[j] = v[j]; + } + } + } + aabb_valid = true; +} + +void Mesh::calc_bsph() +{ + // the cast is to force calling the const version which doesn't invalidate + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { + return; + } + + Vector3 v; + bsph.center = Vector3(0, 0, 0); + + // first find the center + for(unsigned int i=0; i bsph.radius) { + bsph.radius = dist_sq; + } + } + bsph.radius = sqrt(bsph.radius); + + bsph_valid = true; +} +#endif + +void Mesh::update_buffers() +{ + for(int i=0; iget_index_data(); + + for(unsigned int i=0; icalc_normal(); + } + return normal; +} + +void Triangle::transform(const Matrix4x4 &xform) +{ + v[0].transform(xform); + v[1].transform(xform); + v[2].transform(xform); + normal_valid = false; +} + +void Triangle::draw() const +{ + Vector3 n[3]; + n[0] = get_normal(); + n[1] = get_normal(); + n[2] = get_normal(); + + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); + int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL); + + glEnableVertexAttribArray(vloc); + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); + glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(vloc); + glDisableVertexAttribArray(nloc); + CHECKGLERR; +} + +void Triangle::draw_wire() const +{ + static const int idxarr[] = {0, 1, 1, 2, 2, 0}; + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); + + glEnableVertexAttribArray(vloc); + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); + + glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr); + + glDisableVertexAttribArray(vloc); + CHECKGLERR; +} + +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const +{ + Vector3 norm = get_normal(); + + float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm)); + if(area_sq < 1e-5) { + return Vector3(0, 0, 0); + } + + float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm)); + float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm)); + float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm)); + + return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq); +} + +/*bool Triangle::intersect(const Ray &ray, HitPoint *hit) const +{ + Vector3 normal = get_normal(); + + float ndotdir = dot_product(ray.dir, normal); + if(fabs(ndotdir) < 1e-4) { + return false; + } + + Vector3 vertdir = v[0] - ray.origin; + float t = dot_product(normal, vertdir) / ndotdir; + + Vector3 pos = ray.origin + ray.dir * t; + Vector3 bary = calc_barycentric(pos); + + if(bary.x + bary.y + bary.z > 1.00001) { + return false; + } + + if(hit) { + hit->dist = t; + hit->pos = ray.origin + ray.dir * t; + hit->normal = normal; + hit->obj = this; + } + return true; +}*/ diff -r 2918358f5e6d -r e46529a5d057 src/mesh.h --- a/src/mesh.h Sat Aug 17 16:10:26 2013 +0300 +++ b/src/mesh.h Sat Aug 17 23:51:24 2013 +0300 @@ -1,8 +1,213 @@ #ifndef MESH_H_ #define MESH_H_ -class Mesh { - // TODO +#include +#include +#include +//#include "geom.h" + +enum { + MESH_ATTR_VERTEX, + MESH_ATTR_NORMAL, + MESH_ATTR_TANGENT, + MESH_ATTR_TEXCOORD, + MESH_ATTR_COLOR, + MESH_ATTR_BONEWEIGHTS, + MESH_ATTR_BONEIDX, + + NUM_MESH_ATTR }; +// intersection mode flags +enum { + ISECT_DEFAULT = 0, // default (whole mesh, all intersections) + ISECT_FRONT = 1, // front-faces only + ISECT_FACE = 2, // return intersected face pointer instead of mesh + ISECT_VERTICES = 4 // return (?) TODO +}; + +class XFormNode; + + +class Triangle { +public: + Vector3 v[3]; + Vector3 normal; + bool normal_valid; + int id; + + Triangle(); + Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2); + Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0); + + /// calculate normal (quite expensive) + void calc_normal(); + const Vector3 &get_normal() const; + + void transform(const Matrix4x4 &xform); + + void draw() const; + void draw_wire() const; + + /// calculate barycentric coordinates of a point + Vector3 calc_barycentric(const Vector3 &pos) const; + + //bool intersect(const Ray &ray, HitPoint *hit = 0) const; +}; + + +class Mesh { +private: + std::string name; + unsigned int nverts, nfaces; + + // current value for each attribute for the immedate mode + // interface. + Vector4 cur_val[NUM_MESH_ATTR]; + + unsigned int buffer_objects[NUM_MESH_ATTR + 1]; + + // vertex attribute data and buffer objects + struct { + int nelem; // number of elements per attribute range: [1, 4] + std::vector data; + unsigned int vbo; + mutable bool vbo_valid; // if this is false, the vbo needs updating from the data + mutable bool data_valid; // if this is false, the data needs to be pulled from the vbo + //int sdr_loc; + } vattr[NUM_MESH_ATTR]; + + static int global_sdr_loc[NUM_MESH_ATTR]; + + std::vector bones; // bones affecting this mesh + + // index data and buffer object + std::vector idata; + unsigned int ibo; + mutable bool ibo_valid; + mutable bool idata_valid; + + // index buffer object for wireframe rendering (constructed on demand) + unsigned int wire_ibo; + mutable bool wire_ibo_valid; + + // axis-aligned bounding box + /*mutable AABox aabb; + mutable bool aabb_valid; + + // bounding sphere + mutable Sphere bsph; + mutable bool bsph_valid;*/ + + // keeps the last intersected face + mutable Triangle hitface; + // keeps the last intersected vertex position + mutable Vector3 hitvert; + + void calc_aabb(); + void calc_bsph(); + + static unsigned int intersect_mode; + static float vertex_sel_dist; + + static float vis_vecsize; + + /// update the VBOs after data has changed (invalid vbo/ibo) + void update_buffers(); + /// construct/update the wireframe index buffer (called from draw_wire). + void update_wire_ibo(); + + +public: + Mesh(); + ~Mesh(); + + void set_name(const char *name); + const char *get_name() const; + + bool has_attrib(int attr) const; + + // clears everything about this mesh, and returns to the newly constructed state + void clear(); + + // access the vertex attribute data + // if vdata == 0, space is just allocated + float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo + float *get_attrib_data(int attrib); // invalidates vbo + const float *get_attrib_data(int attrib) const; + + // simple access to any particular attribute + void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo + Vector4 get_attrib(int attrib, int idx) const; + + // ... same for index data + unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo + unsigned int *get_index_data(); // invalidates ibo + const unsigned int *get_index_data() const; + + void append(const Mesh &mesh); + + // immediate-mode style mesh construction interface + void vertex(float x, float y, float z); + void normal(float nx, float ny, float nz); + void tangent(float tx, float ty, float tz); + void texcoord(float u, float v, float w); + void boneweights(float w1, float w2, float w3, float w4); + void boneidx(int idx1, int idx2, int idx3, int idx4); + + /* apply a transformation to the vertices and its inverse-transpose + * to the normals and tangents. + */ + void apply_xform(const Matrix4x4 &xform); + void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform); + + // adds a bone and returns its index + int add_bone(XFormNode *bone); + const XFormNode *get_bone(int idx) const; + int get_bones_count() const; + + // access the shader attribute locations + static void set_attrib_location(int attr, int loc); + static int get_attrib_location(int attr); + static void clear_attrib_locations(); + + static void set_vis_vecsize(float sz); + static float get_vis_vecsize(); + + void draw() const; + void draw_wire() const; + void draw_vertices() const; + void draw_normals() const; + void draw_tangents() const; + +#if 0 + /** get the bounding box in local space. The result will be cached, and subsequent + * calls will return the same box. The cache gets invalidated by any functions that can affect + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). + * @{ */ + void get_aabbox(Vector3 *vmin, Vector3 *vmax) const; + const AABox &get_aabbox() const; + /// @} + + /** get the bounding sphere in local space. The result will be cached, and subsequent + * calls will return the same box. The cache gets invalidated by any functions that can affect + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). + * @{ */ + float get_bsphere(Vector3 *center, float *rad) const; + const Sphere &get_bsphere() const; + + static void set_intersect_mode(unsigned int mode); + static unsigned int get_intersect_mode(); + static void set_vertex_select_distance(float dist); + static float get_vertex_select_distance(); + + /** Find the intersection between the mesh and a ray. + * XXX Brute force at the moment, not intended to be used for anything other than picking in tools. + * If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it! + */ + bool intersect(const Ray &ray, HitPoint *hit = 0) const; +#endif +}; + + #endif // MESH_H_ diff -r 2918358f5e6d -r e46529a5d057 src/opengl.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opengl.cc Sat Aug 17 23:51:24 2013 +0300 @@ -0,0 +1,29 @@ +#include "opengl.h" + +void init_opengl() +{ +#ifdef __GLEW_H__ + glewInit(); +#endif +} + +const char *strglerr(int err) +{ + static const char *errnames[] = { + "GL_INVALID_ENUM", + "GL_INVALID_VALUE", + "GL_INVALID_OPERATION", + "GL_STACK_OVERFLOW", + "GL_STACK_UNDERFLOW", + "GL_OUT_OF_MEMORY", + "GL_INVALID_FRAMEBUFFER_OPERATION" + }; + + if(!err) { + return "GL_NO_ERROR"; + } + if(err < GL_INVALID_ENUM || err > GL_OUT_OF_MEMORY) { + return ""; + } + return errnames[err - GL_INVALID_ENUM]; +} diff -r 2918358f5e6d -r e46529a5d057 src/opengl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opengl.h Sat Aug 17 23:51:24 2013 +0300 @@ -0,0 +1,71 @@ +#ifndef OPENGL_H_ +#define OPENGL_H_ + +#include + +#ifdef __APPLE__ +#include "TargetConditionals.h" + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +/* iOS */ +#include +#include + +#define GL_CLAMP GL_CLAMP_TO_EDGE +#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES + +#undef USE_OLDGL + +#define GL_WRITE_ONLY GL_WRITE_ONLY_OES +#define glMapBuffer glMapBufferOES +#define glUnmapBuffer glUnmapBufferOES + +#else +/* MacOS X */ +#include +#include + +#define USE_OLDGL +#endif + +#else +/* UNIX or Windows */ +#include +#include + +#define USE_OLDGL +#endif + +#ifndef GL_RGB16F +#define GL_RGB16F 0x881b +#endif +#ifndef GL_RGBA16F +#define GL_RGBA16F 0x881a +#endif +#ifndef GL_RGB32F +#define GL_RGB32F 0x8815 +#endif +#ifndef GL_RGBA32F +#define GL_RGBA32F 0x8814 +#endif +#ifndef GL_LUMINANCE16F +#define GL_LUMINANCE16F 0x881e +#endif +#ifndef GL_LUMINANCE32F +#define GL_LUMINANCE32F 0x8818 +#endif + +#define CHECKGLERR \ + do { \ + int err = glGetError(); \ + if(err) { \ + fprintf(stderr, "%s:%d: OpenGL error 0x%x: %s\n", __FILE__, __LINE__, err, strglerr(err)); \ + abort(); \ + } \ + } while(0) + +void init_opengl(); + +const char *strglerr(int err); + +#endif // OPENGL_H_ diff -r 2918358f5e6d -r e46529a5d057 src/vmath.h --- a/src/vmath.h Sat Aug 17 16:10:26 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -#ifndef VMATH_H_ -#define VMATH_H_ - -class Vector3 { -public: - float x, y, z; - - Vector3() : x(0), y(0), z(0) {} - Vector3(float x, float y, float z) { - this->x = x; - this->y = y; - this->z = z; - } -}; - -class Vector4 { -public: - float x, y, z, w; - - Vector4() : x(0), y(0), z(0), w(1) {} - Vector4(float x, float y, float z, float w) { - this->x = x; - this->y = y; - this->z = z; - this->w = w; - } -}; - -#endif // VMATH_H_ diff -r 2918358f5e6d -r e46529a5d057 src/xform_node.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xform_node.cc Sat Aug 17 23:51:24 2013 +0300 @@ -0,0 +1,370 @@ +#include +#include +#include "xform_node.h" +#include "anim/anim.h" +#include "anim/track.h" + +static inline anm_interpolator track_interpolator(Interp in); +static inline anm_extrapolator track_extrapolator(Extrap ex); + +XFormNode::XFormNode() +{ + anm = new anm_node; + anm_init_node(anm); +} + +XFormNode::~XFormNode() +{ + anm_destroy_node(anm); + delete anm; +} + +void XFormNode::set_name(const char *name) +{ + anm_set_node_name(anm, name); +} + +const char *XFormNode::get_name() const +{ + return anm_get_node_name(anm); +} + +void XFormNode::set_interpolator(Interp in) +{ + anm_set_interpolator(anm, track_interpolator(in)); + interp = in; +} + +Interp XFormNode::get_interpolator() const +{ + return interp; +} + +void XFormNode::set_extrapolator(Extrap ex) +{ + anm_set_extrapolator(anm, track_extrapolator(ex)); + extrap = ex; +} + +Extrap XFormNode::get_extrapolator() const +{ + return extrap; +} + +void XFormNode::add_child(XFormNode *child) +{ + children.push_back(child); + anm_link_node(anm, child->anm); +} + +void XFormNode::remove_child(XFormNode *child) +{ + std::vector::iterator it; + it = std::find(children.begin(), children.end(), child); + if(it != children.end()) { + children.erase(it); + anm_unlink_node(anm, child->anm); + } +} + +int XFormNode::get_children_count() const +{ + return (int)children.size(); +} + +XFormNode *XFormNode::get_child(int idx) +{ + if(idx >= 0 && idx < get_children_count()) { + return children[idx]; + } + return 0; +} + +const XFormNode *XFormNode::get_child(int idx) const +{ + if(idx >= 0 && idx < get_children_count()) { + return children[idx]; + } + return 0; +} + +void XFormNode::set_position(const Vector3 &pos, long tmsec) +{ + anm_set_position(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec)); +} + +Vector3 XFormNode::get_node_position(long tmsec) const +{ + vec3_t p = anm_get_node_position(anm, ANM_MSEC2TM(tmsec)); + return Vector3(p.x, p.y, p.z); +} + +void XFormNode::set_rotation(const Quaternion &quat, long tmsec) +{ + anm_set_rotation(anm, quat_cons(quat.s, quat.v.x, quat.v.y, quat.v.z), ANM_MSEC2TM(tmsec)); +} + +Quaternion XFormNode::get_node_rotation(long tmsec) const +{ + quat_t q = anm_get_node_rotation(anm, ANM_MSEC2TM(tmsec)); + return Quaternion(q.w, q.x, q.y, q.z); +} + +void XFormNode::set_scaling(const Vector3 &pos, long tmsec) +{ + anm_set_scaling(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec)); +} + +Vector3 XFormNode::get_node_scaling(long tmsec) const +{ + vec3_t s = anm_get_node_scaling(anm, ANM_MSEC2TM(tmsec)); + return Vector3(s.x, s.y, s.z); +} + +// these take hierarchy into account +Vector3 XFormNode::get_position(long tmsec) const +{ + vec3_t v = anm_get_position(anm, ANM_MSEC2TM(tmsec)); + return Vector3(v.x, v.y, v.z); +} + +Quaternion XFormNode::get_rotation(long tmsec) const +{ + quat_t q = anm_get_rotation(anm, tmsec); + return Quaternion(q.w, q.x, q.y, q.z); +} + +Vector3 XFormNode::get_scaling(long tmsec) const +{ + vec3_t v = anm_get_scaling(anm, ANM_MSEC2TM(tmsec)); + return Vector3(v.x, v.y, v.z); +} + +void XFormNode::set_pivot(const Vector3 &pivot) +{ + anm_set_pivot(anm, v3_cons(pivot.x, pivot.y, pivot.z)); +} + +Vector3 XFormNode::get_pivot() const +{ + vec3_t p = anm_get_pivot(anm); + return Vector3(p.x, p.y, p.z); +} + +void XFormNode::set_local_matrix(const Matrix4x4 &mat) +{ + local_matrix = mat; +} + +const Matrix4x4 &XFormNode::get_local_matrix() const +{ + return local_matrix; +} + +void XFormNode::set_bone_matrix(const Matrix4x4 &bmat) +{ + bone_matrix = bmat; +} + +const Matrix4x4 &XFormNode::get_bone_matrix() const +{ + return bone_matrix; +} + +#define FOO + +void XFormNode::get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const +{ + anm_time_t tm = ANM_MSEC2TM(tmsec); + + if(mat) { + anm_get_node_matrix(anm, (scalar_t(*)[4])mat, tm); +#ifdef FOO + *mat = local_matrix * *mat; +#else + *mat = *mat * local_matrix; +#endif + } + if(inv_mat) { + anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm); + } +} + +void XFormNode::get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const +{ + anm_time_t tm = ANM_MSEC2TM(tmsec); + + if(mat) { + anm_get_matrix(anm, (scalar_t(*)[4])mat, tm); +#ifdef FOO + *mat = local_matrix * *mat; +#else + *mat = *mat * local_matrix; +#endif + } + if(inv_mat) { + anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm); + } +} + + +// ---- Track ---- + +Track::Track() +{ + trk = new anm_track; + anm_init_track(trk); +} + +Track::~Track() +{ + anm_destroy_track(trk); + delete trk; +} + +Track::Track(const Track &rhs) +{ + trk = new anm_track; + anm_init_track(trk); + anm_copy_track(trk, rhs.trk); + interp = rhs.interp; + extrap = rhs.extrap; +} + +Track &Track::operator =(const Track &rhs) +{ + if(&rhs == this) { + return *this; + } + + anm_copy_track(trk, rhs.trk); + interp = rhs.interp; + extrap = rhs.extrap; + return *this; +} + + +void Track::set_interpolator(Interp in) +{ + anm_set_track_interpolator(trk, track_interpolator(in)); + interp = in; +} + +Interp Track::get_interpolator() const +{ + return interp; +} + +void Track::set_extrapolator(Extrap ex) +{ + anm_set_track_extrapolator(trk, track_extrapolator(ex)); + extrap = ex; +} + +Extrap Track::get_extrapolator() const +{ + return extrap; +} + +void Track::set_default(double def) +{ + anm_set_track_default(trk, def); +} + +void Track::set_value(float val, long tmsec) +{ + anm_set_value(trk, ANM_MSEC2TM(tmsec), val); +} + +float Track::get_value(long tmsec) const +{ + return anm_get_value(trk, ANM_MSEC2TM(tmsec)); +} + +float Track::operator ()(long tmsec) const +{ + return anm_get_value(trk, ANM_MSEC2TM(tmsec)); +} + + +// ---- Track3 ---- + +void Track3::set_interpolator(Interp in) +{ + for(int i=0; i<3; i++) { + track[i].set_interpolator(in); + } +} + +Interp Track3::get_interpolator() const +{ + return track[0].get_interpolator(); +} + +void Track3::set_extrapolator(Extrap ex) +{ + for(int i=0; i<3; i++) { + track[i].set_extrapolator(ex); + } +} + +Extrap Track3::get_extrapolator() const +{ + return track[0].get_extrapolator(); +} + +void Track3::set_default(const Vector3 &def) +{ + for(int i=0; i<3; i++) { + track[i].set_default(def[i]); + } +} + +void Track3::set_value(const Vector3 &val, long tmsec) +{ + for(int i=0; i<3; i++) { + track[i].set_value(val[i], tmsec); + } +} + +Vector3 Track3::get_value(long tmsec) const +{ + return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec)); +} + +Vector3 Track3::operator ()(long tmsec) const +{ + return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec)); +} + + +static inline anm_interpolator track_interpolator(Interp in) +{ + switch(in) { + case INTERP_STEP: + return ANM_INTERP_STEP; + case INTERP_LINEAR: + return ANM_INTERP_LINEAR; + case INTERP_CUBIC: + return ANM_INTERP_CUBIC; + } + + assert(0); + return ANM_INTERP_STEP; +} + +static inline anm_extrapolator track_extrapolator(Extrap ex) +{ + switch(ex) { + case EXTRAP_EXTEND: + return ANM_EXTRAP_EXTEND; + case EXTRAP_CLAMP: + return ANM_EXTRAP_CLAMP; + case EXTRAP_REPEAT: + return ANM_EXTRAP_REPEAT; + } + + assert(0); + return ANM_EXTRAP_EXTEND; +} + diff -r 2918358f5e6d -r e46529a5d057 src/xform_node.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xform_node.h Sat Aug 17 23:51:24 2013 +0300 @@ -0,0 +1,134 @@ +/* +TODO: add multiple animations per node in libanim (i.e. multiple sets of tracks) +*/ +#ifndef XFORM_NODE_H_ +#define XFORM_NODE_H_ + +#include +#include "vmath/vector.h" +#include "vmath/quat.h" +#include "vmath/matrix.h" + +enum Interp { INTERP_STEP, INTERP_LINEAR, INTERP_CUBIC }; +enum Extrap { EXTRAP_EXTEND, EXTRAP_CLAMP, EXTRAP_REPEAT }; + +struct anm_node; +struct anm_track; + +// XXX all time arguments are milliseconds + +class XFormNode { +private: + struct anm_node *anm; + std::vector children; + + Interp interp; + Extrap extrap; + + Matrix4x4 local_matrix; + Matrix4x4 bone_matrix; + + XFormNode(const XFormNode &node) {} + XFormNode &operator =(const XFormNode &node) { return *this; } + +public: + XFormNode(); + virtual ~XFormNode(); + + void set_name(const char *name); + const char *get_name() const; + + void set_interpolator(Interp in); + Interp get_interpolator() const; + void set_extrapolator(Extrap ex); + Extrap get_extrapolator() const; + + // children management + void add_child(XFormNode *child); + void remove_child(XFormNode *child); + + int get_children_count() const; + XFormNode *get_child(int idx); + const XFormNode *get_child(int idx) const; + + + void set_position(const Vector3 &pos, long tmsec = 0); + Vector3 get_node_position(long tmsec = 0) const; + + void set_rotation(const Quaternion &quat, long tmsec = 0); + Quaternion get_node_rotation(long tmsec = 0) const; + + void set_scaling(const Vector3 &pos, long tmsec = 0); + Vector3 get_node_scaling(long tmsec = 0) const; + + // these take hierarchy into account + Vector3 get_position(long tmsec = 0) const; + Quaternion get_rotation(long tmsec = 0) const; + Vector3 get_scaling(long tmsec = 0) const; + + void set_pivot(const Vector3 &pivot); + Vector3 get_pivot() const; + + // the local matrix is concatenated with the regular node/anim matrix + void set_local_matrix(const Matrix4x4 &mat); + const Matrix4x4 &get_local_matrix() const; + + // for bone nodes, the transformation of the bone in bind position + void set_bone_matrix(const Matrix4x4 &bmat); + const Matrix4x4 &get_bone_matrix() const; + + // node transformation alone + void get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const; + + // node transformation taking hierarchy into account + void get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const; +}; + + +class Track { +private: + struct anm_track *trk; + Interp interp; + Extrap extrap; + +public: + Track(); + ~Track(); + + Track(const Track &trk); + Track &operator =(const Track &trk); + + void set_interpolator(Interp in); + Interp get_interpolator() const; + void set_extrapolator(Extrap ex); + Extrap get_extrapolator() const; + + void set_default(double def); + + void set_value(float val, long tmsec = 0); + float get_value(long tmsec = 0) const; + + // the same as get_value + float operator ()(long tmsec = 0) const; +}; + +class Track3 { +private: + Track track[3]; + +public: + void set_interpolator(Interp in); + Interp get_interpolator() const; + void set_extrapolator(Extrap ex); + Extrap get_extrapolator() const; + + void set_default(const Vector3 &def); + + void set_value(const Vector3 &val, long tmsec = 0); + Vector3 get_value(long tmsec = 0) const; + + // the same as get_value + Vector3 operator ()(long tmsec = 0) const; +}; + +#endif /* XFORM_NODE_H_ */