coeng
changeset 8:8cce82794f90
seems to work nicely
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 15 Feb 2015 05:14:20 +0200 |
parents | af24cfbdf9b6 |
children | 49fdb15f1100 |
files | Makefile src/co_collider.cc src/co_collider.h src/co_mesh.cc src/co_mesh.h src/co_phys.cc src/co_phys.h src/co_xform.cc src/co_xform.h src/comp.cc src/comp.h src/geom.cc src/geom.h src/gobj.cc src/mesh.cc src/mesh.h src/objfile.c src/objfile.h src/opengl.cc src/opengl.h src/shader.cc src/shader.h src/sim.cc src/sim.h src/test.cc |
diffstat | 25 files changed, 3011 insertions(+), 40 deletions(-) [+] |
line diff
1.1 --- a/Makefile Sat Feb 14 10:08:00 2015 +0200 1.2 +++ b/Makefile Sun Feb 15 05:14:20 2015 +0200 1.3 @@ -1,5 +1,6 @@ 1.4 +csrc = $(wildcard src/*.c) 1.5 ccsrc = $(wildcard src/*.cc) 1.6 -obj = $(ccsrc:.cc=.o) 1.7 +obj = $(ccsrc:.cc=.o) $(csrc:.c=.o) 1.8 dep = $(obj:.o=.d) 1.9 bin = test 1.10 1.11 @@ -21,6 +22,9 @@ 1.12 1.13 -include $(dep) 1.14 1.15 +%.d: %.c 1.16 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 1.17 + 1.18 %.d: %.cc 1.19 @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ 1.20
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/co_collider.cc Sun Feb 15 05:14:20 2015 +0200 2.3 @@ -0,0 +1,53 @@ 2.4 +#include "co_collider.h" 2.5 +#include "co_xform.h" 2.6 +#include "gobj.h" 2.7 + 2.8 +static CoCollider reg_co_col; 2.9 + 2.10 +static Component *cons_collider() { return new CoCollider; } 2.11 + 2.12 +CoCollider::CoCollider() 2.13 +{ 2.14 + name = "collider"; 2.15 + shape = 0; 2.16 + 2.17 + register_component(name, cons_collider); 2.18 +} 2.19 + 2.20 +CoCollider::~CoCollider() 2.21 +{ 2.22 + delete shape; 2.23 +} 2.24 + 2.25 +const char **CoCollider::update_before() const 2.26 +{ 2.27 + static const char *before[] = { "rigid", 0 }; 2.28 + return before; 2.29 +} 2.30 + 2.31 +void CoCollider::update(float dt) 2.32 +{ 2.33 + // set the shape transform according to the last value of the CoXForm 2.34 + if(!shape) return; 2.35 + 2.36 + CoXForm *co_xform = COCAST(CoXForm, gobj->get_component("xform")); 2.37 + if(co_xform) { 2.38 + shape->set_transform(co_xform->xform); 2.39 + } 2.40 +} 2.41 + 2.42 +bool CoCollider::collide(const CoCollider *col2, HitPoint *hit) const 2.43 +{ 2.44 + if(!shape || !col2->shape) { 2.45 + return false; 2.46 + } 2.47 + return shape->collide(col2->shape, hit); 2.48 +} 2.49 + 2.50 +CoCollider *gobj_co_collider(const GObject *obj, bool nofail) 2.51 +{ 2.52 + CoCollider *co = COCAST(CoCollider, obj->get_component("collider")); 2.53 + if(co) return co; 2.54 + 2.55 + return nofail ? ®_co_col : 0; 2.56 +}
3.1 --- a/src/co_collider.h Sat Feb 14 10:08:00 2015 +0200 3.2 +++ b/src/co_collider.h Sun Feb 15 05:14:20 2015 +0200 3.3 @@ -4,9 +4,21 @@ 3.4 #include "comp.h" 3.5 #include "geom.h" 3.6 3.7 -class CoCollider { 3.8 +class CoCollider : public Component { 3.9 +protected: 3.10 + const char **update_before() const; 3.11 + 3.12 public: 3.13 GeomShape *shape; 3.14 + 3.15 + CoCollider(); 3.16 + ~CoCollider(); 3.17 + 3.18 + void update(float dt); 3.19 + 3.20 + bool collide(const CoCollider *col2, HitPoint *hit = 0) const; 3.21 }; 3.22 3.23 +CoCollider *gobj_co_collider(const GObject *obj, bool nofail = true); 3.24 + 3.25 #endif // CO_COLLIDER_H_
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/co_mesh.cc Sun Feb 15 05:14:20 2015 +0200 4.3 @@ -0,0 +1,46 @@ 4.4 +#include "opengl.h" 4.5 +#include "co_mesh.h" 4.6 +#include "co_xform.h" 4.7 +#include "gobj.h" 4.8 + 4.9 +static CoMesh reg_co_mesh; 4.10 +static Component *cons_co_mesh() { return new CoMesh; } 4.11 + 4.12 +CoMesh::CoMesh() 4.13 +{ 4.14 + name = "mesh"; 4.15 + mesh = 0; 4.16 + 4.17 + register_component(name, cons_co_mesh); 4.18 +} 4.19 + 4.20 +CoMesh::~CoMesh() 4.21 +{ 4.22 + delete mesh; 4.23 +} 4.24 + 4.25 +void CoMesh::draw() const 4.26 +{ 4.27 + if(!mesh) return; 4.28 + 4.29 + CoXForm *co_xform = COCAST(CoXForm, gobj->get_component("xform")); 4.30 + if(co_xform) { 4.31 + glPushMatrix(); 4.32 + glMultTransposeMatrixf(co_xform->xform[0]); 4.33 + } 4.34 + 4.35 + mesh->draw(); 4.36 + 4.37 + if(co_xform) { 4.38 + glPopMatrix(); 4.39 + } 4.40 +} 4.41 + 4.42 + 4.43 +CoMesh *gobj_co_mesh(const GObject *obj, bool nofail) 4.44 +{ 4.45 + CoMesh *co = COCAST(CoMesh, obj->get_component("mesh")); 4.46 + if(co) return co; 4.47 + 4.48 + return nofail ? ®_co_mesh : 0; 4.49 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/co_mesh.h Sun Feb 15 05:14:20 2015 +0200 5.3 @@ -0,0 +1,20 @@ 5.4 +#ifndef CO_MESH_H_ 5.5 +#define CO_MESH_H_ 5.6 + 5.7 +#include "comp.h" 5.8 +#include "mesh.h" 5.9 +#include "gobj.h" 5.10 + 5.11 +class CoMesh : public Component { 5.12 +public: 5.13 + Mesh *mesh; 5.14 + 5.15 + CoMesh(); 5.16 + ~CoMesh(); 5.17 + 5.18 + void draw() const; 5.19 +}; 5.20 + 5.21 +CoMesh *gobj_co_mesh(const GObject *obj, bool nofail = true); 5.22 + 5.23 +#endif // CO_MESH_H_
6.1 --- a/src/co_phys.cc Sat Feb 14 10:08:00 2015 +0200 6.2 +++ b/src/co_phys.cc Sun Feb 15 05:14:20 2015 +0200 6.3 @@ -1,6 +1,10 @@ 6.4 #include <assert.h> 6.5 +#include <vmath/vmath.h> 6.6 #include "co_phys.h" 6.7 #include "sim.h" 6.8 +#include "co_collider.h" 6.9 + 6.10 +#define FIXED_MASS 1e9 6.11 6.12 static CoRigid reg_co_rigid; 6.13 6.14 @@ -9,10 +13,12 @@ 6.15 CoRigid::CoRigid() 6.16 { 6.17 mass = 1.0; 6.18 - elast = 0.5; 6.19 + elast = 0.85; 6.20 friction = 0.0; 6.21 + fixed = false; 6.22 6.23 name = "rigid"; 6.24 + co_prs = 0; 6.25 6.26 register_component(name, cons_rigid); 6.27 } 6.28 @@ -23,6 +29,26 @@ 6.29 return before; 6.30 } 6.31 6.32 +void CoRigid::set_fixed(bool f) 6.33 +{ 6.34 + fixed = f; 6.35 +} 6.36 + 6.37 +bool CoRigid::get_fixed() const 6.38 +{ 6.39 + return fixed; 6.40 +} 6.41 + 6.42 +void CoRigid::set_mass(float mass) 6.43 +{ 6.44 + this->mass = mass; 6.45 +} 6.46 + 6.47 +float CoRigid::get_mass() const 6.48 +{ 6.49 + return fixed ? FIXED_MASS : mass; 6.50 +} 6.51 + 6.52 void CoRigid::add_impulse(const Vector3 &v) 6.53 { 6.54 impulse += v; 6.55 @@ -30,7 +56,7 @@ 6.56 6.57 void CoRigid::update(float dt) 6.58 { 6.59 - if(!gobj) return; 6.60 + if(!gobj || fixed) return; 6.61 6.62 if(!co_prs) { 6.63 if(!(co_prs = COCAST(CoPRS, gobj->get_component("prs")))) { 6.64 @@ -39,6 +65,23 @@ 6.65 } 6.66 } 6.67 6.68 + // collision detection 6.69 + CoCollider *co_col; 6.70 + if(world && (co_col = gobj_co_collider(gobj, COGET_FAIL))) { 6.71 + HitPoint hit; 6.72 + 6.73 + // dot product subexpression is to ignore collisions when moving OUT 6.74 + // of the object after an interpenetration 6.75 + if(world->collide(co_col, &hit) && dot_product(vel, hit.normal) <= 0.0) { 6.76 + Vector3 refl = -vel.reflection(hit.normal); 6.77 + Vector3 vert = hit.normal * dot_product(refl, hit.normal); 6.78 + Vector3 tang = refl - vert; 6.79 + vel = vert * elast + tang * friction; 6.80 + // TODO add an impulse to the other object and take account of the relative masses 6.81 + } 6.82 + } 6.83 + 6.84 + 6.85 float damping = world ? world->get_damping() : 0.005; 6.86 6.87 Vector3 newpos = co_prs->pos + vel * dt; 6.88 @@ -51,8 +94,16 @@ 6.89 } 6.90 6.91 vel = (vel - vel * damping * dt) + accel * dt; 6.92 - 6.93 - // TODO collisions 6.94 - 6.95 + if(vel.length() < 1e-3) { 6.96 + vel.x = vel.y = vel.z = 0.0f; 6.97 + } 6.98 co_prs->pos = newpos; 6.99 } 6.100 + 6.101 +CoRigid *gobj_co_rigid(const GObject *obj, bool nofail) 6.102 +{ 6.103 + CoRigid *co = COCAST(CoRigid, obj->get_component("rigid")); 6.104 + if(co) return co; 6.105 + 6.106 + return nofail ? ®_co_rigid : 0; 6.107 +}
7.1 --- a/src/co_phys.h Sat Feb 14 10:08:00 2015 +0200 7.2 +++ b/src/co_phys.h Sun Feb 15 05:14:20 2015 +0200 7.3 @@ -15,15 +15,25 @@ 7.4 7.5 public: 7.6 SimWorld *world; 7.7 + bool fixed; 7.8 float mass, elast, friction; 7.9 Vector3 vel, force; 7.10 Vector3 impulse; 7.11 7.12 CoRigid(); 7.13 7.14 + void set_fixed(bool f); 7.15 + bool get_fixed() const; 7.16 + 7.17 + void set_mass(float mass); 7.18 + float get_mass() const; 7.19 + 7.20 void add_impulse(const Vector3 &v); 7.21 7.22 void update(float dt); 7.23 }; 7.24 7.25 +// helper component accessors 7.26 +CoRigid *gobj_co_rigid(const GObject *obj, bool nofail = true); 7.27 + 7.28 #endif // COMP_PHYS_H_
8.1 --- a/src/co_xform.cc Sat Feb 14 10:08:00 2015 +0200 8.2 +++ b/src/co_xform.cc Sun Feb 15 05:14:20 2015 +0200 8.3 @@ -21,6 +21,7 @@ 8.4 : scale(1, 1, 1) 8.5 { 8.6 name = "prs"; 8.7 + co_xform = 0; 8.8 8.9 register_component(name, cons_prs); 8.10 } 8.11 @@ -50,3 +51,19 @@ 8.12 8.13 co_xform->xform = rmat * tmat * smat; 8.14 } 8.15 + 8.16 +CoXForm *gobj_co_xform(const GObject *obj, bool nofail) 8.17 +{ 8.18 + CoXForm *co = COCAST(CoXForm, obj->get_component("xform")); 8.19 + if(co) return co; 8.20 + 8.21 + return nofail ? ®_co_xform : 0; 8.22 +} 8.23 + 8.24 +CoPRS *gobj_co_prs(const GObject *obj, bool nofail) 8.25 +{ 8.26 + CoPRS *co = COCAST(CoPRS, obj->get_component("prs")); 8.27 + if(co) return co; 8.28 + 8.29 + return nofail ? ®_co_prs : 0; 8.30 +}
9.1 --- a/src/co_xform.h Sat Feb 14 10:08:00 2015 +0200 9.2 +++ b/src/co_xform.h Sun Feb 15 05:14:20 2015 +0200 9.3 @@ -26,5 +26,9 @@ 9.4 void update(float dt); 9.5 }; 9.6 9.7 +// helper component accessors 9.8 +CoXForm *gobj_co_xform(const GObject *obj, bool nofail = true); 9.9 +CoPRS *gobj_co_prs(const GObject *obj, bool nofail = true); 9.10 + 9.11 9.12 #endif // CO_XFORM_H_
10.1 --- a/src/comp.cc Sat Feb 14 10:08:00 2015 +0200 10.2 +++ b/src/comp.cc Sun Feb 15 05:14:20 2015 +0200 10.3 @@ -37,6 +37,11 @@ 10.4 return name; 10.5 } 10.6 10.7 +GObject *Component::get_object() const 10.8 +{ 10.9 + return gobj; 10.10 +} 10.11 + 10.12 void Component::update(float dt) 10.13 { 10.14 }
11.1 --- a/src/comp.h Sat Feb 14 10:08:00 2015 +0200 11.2 +++ b/src/comp.h Sun Feb 15 05:14:20 2015 +0200 11.3 @@ -9,6 +9,10 @@ 11.4 #define COCAST(type, x) dynamic_cast<type*>(x) 11.5 #endif 11.6 11.7 +// for the second arg of the various gobj_co_whatever() functions 11.8 +#define COGET_NOFAIL true 11.9 +#define COGET_FAIL false 11.10 + 11.11 class GObject; 11.12 11.13 class Component { 11.14 @@ -34,6 +38,7 @@ 11.15 virtual ~Component(); 11.16 11.17 const char *get_name() const; 11.18 + GObject *get_object() const; 11.19 11.20 virtual void update(float dt); 11.21 virtual void draw() const;
12.1 --- a/src/geom.cc Sat Feb 14 10:08:00 2015 +0200 12.2 +++ b/src/geom.cc Sun Feb 15 05:14:20 2015 +0200 12.3 @@ -1,3 +1,4 @@ 12.4 +#include "opengl.h" 12.5 #include <float.h> 12.6 #include <algorithm> 12.7 #include "geom.h" 12.8 @@ -20,6 +21,22 @@ 12.9 return type; 12.10 } 12.11 12.12 +void GeomShape::set_transform(const Matrix4x4 &m) 12.13 +{ 12.14 + xform = m; 12.15 + inv_xform = xform.inverse(); 12.16 +} 12.17 + 12.18 +const Matrix4x4 &GeomShape::get_transform() const 12.19 +{ 12.20 + return xform; 12.21 +} 12.22 + 12.23 +const Matrix4x4 &GeomShape::get_inv_transform() const 12.24 +{ 12.25 + return inv_xform; 12.26 +} 12.27 + 12.28 // ---- Sphere class ---- 12.29 12.30 Sphere::Sphere() 12.31 @@ -35,8 +52,15 @@ 12.32 radius = rad; 12.33 } 12.34 12.35 -bool Sphere::intersect(const Ray &ray, HitPoint *hit) const 12.36 +bool Sphere::contains(const Vector3 &pt) const 12.37 { 12.38 + return distance_sq(pt) <= 0.0; 12.39 +} 12.40 + 12.41 +bool Sphere::intersect(const Ray &inray, HitPoint *hit) const 12.42 +{ 12.43 + Ray ray = inray.transformed(inv_xform); 12.44 + 12.45 float a = dot_product(ray.dir, ray.dir); 12.46 float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) + 12.47 2.0 * ray.dir.y * (ray.origin.y - center.y) + 12.48 @@ -68,8 +92,10 @@ 12.49 hit->shape = this; 12.50 hit->data = 0; 12.51 hit->dist = t; 12.52 - hit->pos = ray.origin + ray.dir * t; 12.53 - hit->normal = (hit->pos - center) / radius; 12.54 + 12.55 + Vector3 local_pos = ray.origin + ray.dir * t; 12.56 + hit->pos = inray.origin + inray.dir * t; 12.57 + hit->normal = (local_pos - center) / radius; 12.58 } 12.59 return true; 12.60 } 12.61 @@ -89,12 +115,19 @@ 12.62 12.63 float Sphere::distance(const Vector3 &pt) const 12.64 { 12.65 - return sqrt(distance_sq(pt)); 12.66 + Vector3 local_pt = pt.transformed(inv_xform); 12.67 + return (local_pt - center).length() - radius; 12.68 } 12.69 12.70 float Sphere::distance_sq(const Vector3 &pt) const 12.71 { 12.72 - return (pt - center).length_sq(); 12.73 + Vector3 local_pt = pt.transformed(inv_xform); 12.74 + return (local_pt - center).length_sq() - radius * radius; 12.75 +} 12.76 + 12.77 +void Sphere::draw() const 12.78 +{ 12.79 + // TODO 12.80 } 12.81 12.82 // ---- Plane class ---- 12.83 @@ -142,10 +175,15 @@ 12.84 dist = distance(p1); 12.85 } 12.86 12.87 +bool Plane::contains(const Vector3 &pt) const 12.88 +{ 12.89 + return distance(pt) <= 0.0; 12.90 +} 12.91 12.92 -bool Plane::intersect(const Ray &ray, HitPoint *hit) const 12.93 +bool Plane::intersect(const Ray &inray, HitPoint *hit) const 12.94 { 12.95 - Vector3 pt = Vector3(0, 0, 0) + normal * dist; 12.96 + Ray ray = inray.transformed(inv_xform); 12.97 + Vector3 pt = normal * dist; 12.98 12.99 float ndotdir = dot_product(normal, ray.dir); 12.100 if(fabs(ndotdir) < 1e-4) { 12.101 @@ -156,7 +194,7 @@ 12.102 Vector3 ptdir = pt - ray.origin; 12.103 float t = dot_product(normal, ptdir) / ndotdir; 12.104 12.105 - hit->pos = ray.origin + ray.dir * t; 12.106 + hit->pos = inray.origin + inray.dir * t; 12.107 hit->normal = normal; 12.108 hit->shape = this; 12.109 } 12.110 @@ -187,7 +225,7 @@ 12.111 float Plane::distance(const Vector3 &v) const 12.112 { 12.113 Vector3 pt = normal * dist; 12.114 - return dot_product(v - pt, normal); 12.115 + return dot_product(v.transformed(inv_xform) - pt, normal); 12.116 } 12.117 12.118 float Plane::distance_sq(const Vector3 &v) const 12.119 @@ -196,20 +234,187 @@ 12.120 return d * d; 12.121 } 12.122 12.123 +void Plane::draw() const 12.124 +{ 12.125 + // TODO 12.126 +} 12.127 + 12.128 +// ---- AABox ---- 12.129 + 12.130 +AABox::AABox() 12.131 +{ 12.132 + type = GEOM_AABOX; 12.133 +} 12.134 + 12.135 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax) 12.136 + : min(vmin), max(vmax) 12.137 +{ 12.138 + type = GEOM_AABOX; 12.139 +} 12.140 + 12.141 +void AABox::set_union(const GeomShape *obj1, const GeomShape *obj2) 12.142 +{ 12.143 + const AABox *box1 = (const AABox*)obj1; 12.144 + const AABox *box2 = (const AABox*)obj2; 12.145 + 12.146 + if(!box1 || !box2 || obj1->get_type() != GEOM_AABOX || obj2->get_type() != GEOM_AABOX) { 12.147 + fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); 12.148 + return; 12.149 + } 12.150 + 12.151 + min.x = std::min(box1->min.x, box2->min.x); 12.152 + min.y = std::min(box1->min.y, box2->min.y); 12.153 + min.z = std::min(box1->min.z, box2->min.z); 12.154 + 12.155 + max.x = std::max(box1->max.x, box2->max.x); 12.156 + max.y = std::max(box1->max.y, box2->max.y); 12.157 + max.z = std::max(box1->max.z, box2->max.z); 12.158 +} 12.159 + 12.160 +void AABox::set_intersection(const GeomShape *obj1, const GeomShape *obj2) 12.161 +{ 12.162 + const AABox *box1 = (const AABox*)obj1; 12.163 + const AABox *box2 = (const AABox*)obj2; 12.164 + 12.165 + if(!box1 || !box2 || obj1->get_type() != GEOM_AABOX || obj2->get_type() != GEOM_AABOX) { 12.166 + fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); 12.167 + return; 12.168 + } 12.169 + 12.170 + for(int i=0; i<3; i++) { 12.171 + min[i] = std::max(box1->min[i], box2->min[i]); 12.172 + max[i] = std::min(box1->max[i], box2->max[i]); 12.173 + 12.174 + if(max[i] < min[i]) { 12.175 + max[i] = min[i]; 12.176 + } 12.177 + } 12.178 +} 12.179 + 12.180 +bool AABox::contains(const Vector3 &pt) const 12.181 +{ 12.182 + return pt.x >= min.x && pt.x <= max.x && 12.183 + pt.y >= min.y && pt.y <= max.y && 12.184 + pt.z >= min.z && pt.z <= max.z; 12.185 +} 12.186 + 12.187 +bool AABox::intersect(const Ray &inray, HitPoint *hit) const 12.188 +{ 12.189 + Ray ray = inray.transformed(inv_xform); 12.190 + 12.191 + Vector3 param[2] = {min, max}; 12.192 + Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); 12.193 + int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; 12.194 + 12.195 + float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; 12.196 + float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; 12.197 + float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; 12.198 + float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; 12.199 + 12.200 + if(tmin > tymax || tymin > tmax) { 12.201 + return false; 12.202 + } 12.203 + if(tymin > tmin) { 12.204 + tmin = tymin; 12.205 + } 12.206 + if(tymax < tmax) { 12.207 + tmax = tymax; 12.208 + } 12.209 + 12.210 + float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; 12.211 + float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; 12.212 + 12.213 + if(tmin > tzmax || tzmin > tmax) { 12.214 + return false; 12.215 + } 12.216 + if(tzmin > tmin) { 12.217 + tmin = tzmin; 12.218 + } 12.219 + if(tzmax < tmax) { 12.220 + tmax = tzmax; 12.221 + } 12.222 + 12.223 + float t = tmin < 1e-4 ? tmax : tmin; 12.224 + if(t >= 1e-4) { 12.225 + 12.226 + if(hit) { 12.227 + hit->shape = this; 12.228 + hit->dist = t; 12.229 + hit->pos = inray.origin + inray.dir * t; 12.230 + 12.231 + float min_dist = FLT_MAX; 12.232 + Vector3 offs = min + (max - min) / 2.0; 12.233 + Vector3 local_hit = hit->pos - offs; 12.234 + 12.235 + static const Vector3 axis[] = { 12.236 + Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) 12.237 + }; 12.238 + //int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}}; 12.239 + 12.240 + for(int i=0; i<3; i++) { 12.241 + float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i])); 12.242 + if(dist < min_dist) { 12.243 + min_dist = dist; 12.244 + hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0); 12.245 + //hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]); 12.246 + } 12.247 + } 12.248 + hit->normal.transform(Matrix3x3(xform)); 12.249 + } 12.250 + return true; 12.251 + } 12.252 + return false; 12.253 +} 12.254 + 12.255 +bool AABox::collide(const GeomShape *geom, HitPoint *hit) const 12.256 +{ 12.257 + fprintf(stderr, "%s: not implemented yet\n", __FUNCTION__); 12.258 + return false; 12.259 +} 12.260 + 12.261 +float AABox::distance(const Vector3 &pt) const 12.262 +{ 12.263 + float d = distance_sq(pt); 12.264 + return d * d; 12.265 +} 12.266 + 12.267 +float AABox::distance_sq(const Vector3 &world_pt) const 12.268 +{ 12.269 + Vector3 pt = pt.transformed(inv_xform); 12.270 + 12.271 + float dx = std::max(pt.x - max.x, min.x - pt.x); 12.272 + float dy = std::max(pt.y - max.y, min.y - pt.y); 12.273 + float dz = std::max(pt.z - max.z, min.z - pt.z); 12.274 + 12.275 + return Vector3(dx, dy, dz).length_sq(); 12.276 +} 12.277 + 12.278 +void AABox::draw() const 12.279 +{ 12.280 +} 12.281 + 12.282 12.283 // collision detection functions 12.284 12.285 static bool col_sphere_sphere(const Sphere *a, const Sphere *b, HitPoint *hit) 12.286 { 12.287 - float sum_rad = a->radius + b->radius; 12.288 - Vector3 dir = b->center - a->center; 12.289 + const Matrix4x4 &xforma = a->get_transform(); 12.290 + const Matrix4x4 &xformb = b->get_transform(); 12.291 + 12.292 + Vector3 ca = a->center.transformed(xforma); 12.293 + Vector3 cb = b->center.transformed(xformb); 12.294 + float rada = a->radius * xforma.get_scaling().x; 12.295 + float radb = b->radius * xformb.get_scaling().x; 12.296 + 12.297 + float sum_rad = rada + radb; 12.298 + Vector3 dir = cb - ca; 12.299 float dist_sq = dir.length_sq(); 12.300 bool res = dist_sq <= sum_rad * sum_rad; 12.301 12.302 if(res && hit) { 12.303 - hit->pos = a->center + dir * 0.5; 12.304 + hit->pos = ca + dir * 0.5; 12.305 hit->shape = b; 12.306 - hit->normal = -dir; 12.307 + hit->normal = -dir.normalized(); 12.308 } 12.309 return res; 12.310 } 12.311 @@ -222,18 +427,25 @@ 12.312 12.313 static bool col_sphere_plane(const Sphere *sph, const Plane *plane, HitPoint *hit) 12.314 { 12.315 - float dist = plane->distance(sph->center); 12.316 - bool res = fabs(dist) <= sph->radius; 12.317 + const Matrix4x4 &xform = sph->get_transform(); 12.318 + 12.319 + Vector3 sph_center = sph->center.transformed(xform); 12.320 + float sph_rad = sph->radius * xform.get_scaling().x; 12.321 + 12.322 + float dist = plane->distance(sph_center); 12.323 + bool res = fabs(dist) <= sph_rad; 12.324 12.325 if(res && hit) { 12.326 - Vector3 planept = plane->normal * plane->dist; 12.327 - Vector3 sphdir = sph->center - planept; 12.328 - if(dot_product(sphdir, plane->normal) >= 0.0f) { 12.329 - hit->normal = plane->normal; 12.330 + Vector3 planept = (plane->normal * plane->dist).transformed(plane->get_transform()); 12.331 + Vector3 planenorm = plane->normal.transformed(Matrix3x3(plane->get_transform())); 12.332 + 12.333 + Vector3 sphdir = sph_center - planept; 12.334 + if(dot_product(sphdir, planenorm) >= 0.0f) { 12.335 + hit->normal = planenorm; 12.336 } else { 12.337 - hit->normal = -plane->normal; 12.338 + hit->normal = -planenorm; 12.339 } 12.340 - hit->pos = sph->center - plane->normal * fabs(dist); 12.341 + hit->pos = sph_center - planenorm * fabs(dist); 12.342 hit->shape = plane; 12.343 } 12.344 return res;
13.1 --- a/src/geom.h Sat Feb 14 10:08:00 2015 +0200 13.2 +++ b/src/geom.h Sun Feb 15 05:14:20 2015 +0200 13.3 @@ -14,8 +14,12 @@ 13.4 }; 13.5 13.6 class GeomShape { 13.7 +public: 13.8 + enum Type { GEOM_UNKNOWN, GEOM_SPHERE, GEOM_PLANE, GEOM_AABOX }; 13.9 + 13.10 protected: 13.11 - enum Type { GEOM_UNKNOWN, GEOM_SPHERE, GEOM_PLANE } type; 13.12 + Matrix4x4 xform, inv_xform; 13.13 + Type type; 13.14 13.15 public: 13.16 GeomShape(); 13.17 @@ -23,11 +27,20 @@ 13.18 13.19 virtual Type get_type() const; 13.20 13.21 + // apply an arbitrary transformation before testing intersections and collisions 13.22 + virtual void set_transform(const Matrix4x4 &m); 13.23 + virtual const Matrix4x4 &get_transform() const; 13.24 + virtual const Matrix4x4 &get_inv_transform() const; 13.25 + 13.26 + virtual bool contains(const Vector3 &pt) const = 0; 13.27 virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0; 13.28 virtual bool collide(const GeomShape *geom, HitPoint *hit = 0) const = 0; 13.29 13.30 virtual float distance(const Vector3 &pt) const = 0; 13.31 virtual float distance_sq(const Vector3 &pt) const = 0; 13.32 + 13.33 + // visualize the shape 13.34 + virtual void draw() const = 0; 13.35 }; 13.36 13.37 class Sphere : public GeomShape { 13.38 @@ -38,11 +51,14 @@ 13.39 Sphere(); 13.40 Sphere(const Vector3 &c, float rad); 13.41 13.42 + bool contains(const Vector3 &pt) const; 13.43 bool intersect(const Ray &ray, HitPoint *hit = 0) const; 13.44 bool collide(const GeomShape *geom, HitPoint *hit = 0) const; 13.45 13.46 float distance(const Vector3 &pt) const; 13.47 float distance_sq(const Vector3 &pt) const; 13.48 + 13.49 + void draw() const; 13.50 }; 13.51 13.52 class Plane : public GeomShape { 13.53 @@ -56,11 +72,34 @@ 13.54 Plane(const Vector3 &pos, const Vector3 &norm); 13.55 Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3); 13.56 13.57 + bool contains(const Vector3 &pt) const; 13.58 bool intersect(const Ray &ray, HitPoint *hit = 0) const; 13.59 bool collide(const GeomShape *geom, HitPoint *hit = 0) const; 13.60 13.61 float distance(const Vector3 &pt) const; 13.62 float distance_sq(const Vector3 &pt) const; 13.63 + 13.64 + void draw() const; 13.65 +}; 13.66 + 13.67 +class AABox : public GeomShape { 13.68 +public: 13.69 + Vector3 min, max; 13.70 + 13.71 + AABox(); 13.72 + AABox(const Vector3 &min, const Vector3 &max); 13.73 + 13.74 + void set_union(const GeomShape *obj1, const GeomShape *obj2); 13.75 + void set_intersection(const GeomShape *obj1, const GeomShape *obj2); 13.76 + 13.77 + bool contains(const Vector3 &pt) const; 13.78 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 13.79 + bool collide(const GeomShape *geom, HitPoint *hit = 0) const; 13.80 + 13.81 + float distance(const Vector3 &pt) const; 13.82 + float distance_sq(const Vector3 &pt) const; 13.83 + 13.84 + void draw() const; 13.85 }; 13.86 13.87 #endif // GEOM_H_
14.1 --- a/src/gobj.cc Sat Feb 14 10:08:00 2015 +0200 14.2 +++ b/src/gobj.cc Sun Feb 15 05:14:20 2015 +0200 14.3 @@ -78,7 +78,9 @@ 14.4 sorted = true; 14.5 } 14.6 14.7 + //printf("updating components\n"); 14.8 for(size_t i=0; i<comp.size(); i++) { 14.9 + //printf(" %s\n", comp[i]->get_name()); 14.10 comp[i]->update(dt); 14.11 } 14.12 }
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/src/mesh.cc Sun Feb 15 05:14:20 2015 +0200 15.3 @@ -0,0 +1,1022 @@ 15.4 +#include <stdio.h> 15.5 +#include <stdlib.h> 15.6 +#include <float.h> 15.7 +#include <assert.h> 15.8 +#include "opengl.h" 15.9 +#include "mesh.h" 15.10 +#include "shader.h" 15.11 + 15.12 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5 }; 15.13 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT; 15.14 +float Mesh::vertex_sel_dist = 0.01; 15.15 +float Mesh::vis_vecsize = 1.0; 15.16 + 15.17 +Mesh::Mesh() 15.18 +{ 15.19 + clear(); 15.20 + 15.21 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 15.22 + 15.23 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.24 + vattr[i].vbo = buffer_objects[i]; 15.25 + } 15.26 + ibo = buffer_objects[NUM_MESH_ATTR]; 15.27 + wire_ibo = 0; 15.28 +} 15.29 + 15.30 +Mesh::~Mesh() 15.31 +{ 15.32 + glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects); 15.33 + 15.34 + if(wire_ibo) { 15.35 + glDeleteBuffers(1, &wire_ibo); 15.36 + } 15.37 +} 15.38 + 15.39 +void Mesh::set_name(const char *name) 15.40 +{ 15.41 + this->name = name; 15.42 +} 15.43 + 15.44 +const char *Mesh::get_name() const 15.45 +{ 15.46 + return name.c_str(); 15.47 +} 15.48 + 15.49 +bool Mesh::has_attrib(int attr) const 15.50 +{ 15.51 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 15.52 + return false; 15.53 + } 15.54 + 15.55 + // if neither of these is valid, then nobody has set this attribute 15.56 + return vattr[attr].vbo_valid || vattr[attr].data_valid; 15.57 +} 15.58 + 15.59 +void Mesh::clear() 15.60 +{ 15.61 + //bones.clear(); 15.62 + 15.63 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.64 + vattr[i].nelem = 0; 15.65 + vattr[i].vbo_valid = false; 15.66 + vattr[i].data_valid = false; 15.67 + //vattr[i].sdr_loc = -1; 15.68 + vattr[i].data.clear(); 15.69 + } 15.70 + ibo_valid = idata_valid = false; 15.71 + idata.clear(); 15.72 + 15.73 + wire_ibo_valid = false; 15.74 + 15.75 + nverts = nfaces = 0; 15.76 + 15.77 + bsph_valid = false; 15.78 + aabb_valid = false; 15.79 +} 15.80 + 15.81 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data) 15.82 +{ 15.83 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 15.84 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 15.85 + return 0; 15.86 + } 15.87 + 15.88 + if(nverts && num != nverts) { 15.89 + fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts); 15.90 + return 0; 15.91 + } 15.92 + nverts = num; 15.93 + 15.94 + vattr[attrib].data.clear(); 15.95 + vattr[attrib].nelem = nelem; 15.96 + vattr[attrib].data.resize(num * nelem); 15.97 + 15.98 + if(data) { 15.99 + memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data); 15.100 + } 15.101 + 15.102 + vattr[attrib].data_valid = true; 15.103 + vattr[attrib].vbo_valid = false; 15.104 + return &vattr[attrib].data[0]; 15.105 +} 15.106 + 15.107 +float *Mesh::get_attrib_data(int attrib) 15.108 +{ 15.109 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 15.110 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 15.111 + return 0; 15.112 + } 15.113 + 15.114 + vattr[attrib].vbo_valid = false; 15.115 + return (float*)((const Mesh*)this)->get_attrib_data(attrib); 15.116 +} 15.117 + 15.118 +const float *Mesh::get_attrib_data(int attrib) const 15.119 +{ 15.120 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 15.121 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 15.122 + return 0; 15.123 + } 15.124 + 15.125 + if(!vattr[attrib].data_valid) { 15.126 +#if GL_ES_VERSION_2_0 15.127 + fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__); 15.128 + return 0; 15.129 +#else 15.130 + if(!vattr[attrib].vbo_valid) { 15.131 + fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib); 15.132 + return 0; 15.133 + } 15.134 + 15.135 + // local data copy is unavailable, grab the data from the vbo 15.136 + Mesh *m = (Mesh*)this; 15.137 + m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem); 15.138 + 15.139 + glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo); 15.140 + void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 15.141 + memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float)); 15.142 + glUnmapBuffer(GL_ARRAY_BUFFER); 15.143 + 15.144 + vattr[attrib].data_valid = true; 15.145 +#endif 15.146 + } 15.147 + 15.148 + return &vattr[attrib].data[0]; 15.149 +} 15.150 + 15.151 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v) 15.152 +{ 15.153 + float *data = get_attrib_data(attrib); 15.154 + if(data) { 15.155 + data += idx * vattr[attrib].nelem; 15.156 + for(int i=0; i<vattr[attrib].nelem; i++) { 15.157 + data[i] = v[i]; 15.158 + } 15.159 + } 15.160 +} 15.161 + 15.162 +Vector4 Mesh::get_attrib(int attrib, int idx) const 15.163 +{ 15.164 + Vector4 v(0.0, 0.0, 0.0, 1.0); 15.165 + const float *data = get_attrib_data(attrib); 15.166 + if(data) { 15.167 + data += idx * vattr[attrib].nelem; 15.168 + for(int i=0; i<vattr[attrib].nelem; i++) { 15.169 + v[i] = data[i]; 15.170 + } 15.171 + } 15.172 + return v; 15.173 +} 15.174 + 15.175 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices) 15.176 +{ 15.177 + int nidx = nfaces * 3; 15.178 + if(nidx && num != nidx) { 15.179 + fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx); 15.180 + return 0; 15.181 + } 15.182 + nfaces = num / 3; 15.183 + 15.184 + idata.clear(); 15.185 + idata.resize(num); 15.186 + 15.187 + if(indices) { 15.188 + memcpy(&idata[0], indices, num * sizeof *indices); 15.189 + } 15.190 + 15.191 + idata_valid = true; 15.192 + ibo_valid = false; 15.193 + 15.194 + return &idata[0]; 15.195 +} 15.196 + 15.197 +unsigned int *Mesh::get_index_data() 15.198 +{ 15.199 + ibo_valid = false; 15.200 + return (unsigned int*)((const Mesh*)this)->get_index_data(); 15.201 +} 15.202 + 15.203 +const unsigned int *Mesh::get_index_data() const 15.204 +{ 15.205 + if(!idata_valid) { 15.206 +#if GL_ES_VERSION_2_0 15.207 + fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__); 15.208 + return 0; 15.209 +#else 15.210 + if(!ibo_valid) { 15.211 + fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__); 15.212 + return 0; 15.213 + } 15.214 + 15.215 + // local data copy is unavailable, gram the data from the ibo 15.216 + Mesh *m = (Mesh*)this; 15.217 + int nidx = nfaces * 3; 15.218 + m->idata.resize(nidx); 15.219 + 15.220 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 15.221 + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); 15.222 + memcpy(&m->idata[0], data, nidx * sizeof(unsigned int)); 15.223 + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); 15.224 + 15.225 + idata_valid = true; 15.226 +#endif 15.227 + } 15.228 + 15.229 + return &idata[0]; 15.230 +} 15.231 + 15.232 +void Mesh::append(const Mesh &mesh) 15.233 +{ 15.234 + unsigned int idxoffs = nverts; 15.235 + 15.236 + nverts += mesh.nverts; 15.237 + nfaces += mesh.nfaces; 15.238 + 15.239 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.240 + if(has_attrib(i) && mesh.has_attrib(i)) { 15.241 + // force validating the data arrays 15.242 + get_attrib_data(i); 15.243 + mesh.get_attrib_data(i); 15.244 + 15.245 + // append the mesh data 15.246 + vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end()); 15.247 + } 15.248 + } 15.249 + 15.250 + if(ibo_valid || idata_valid) { 15.251 + // make index arrays valid 15.252 + get_index_data(); 15.253 + mesh.get_index_data(); 15.254 + 15.255 + size_t orig_sz = idata.size(); 15.256 + 15.257 + idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end()); 15.258 + 15.259 + // fixup all the new indices 15.260 + for(size_t i=orig_sz; i<idata.size(); i++) { 15.261 + idata[i] += idxoffs; 15.262 + } 15.263 + } 15.264 + 15.265 + // fuck everything 15.266 + wire_ibo_valid = false; 15.267 + aabb_valid = false; 15.268 + bsph_valid = false; 15.269 +} 15.270 + 15.271 +// assemble a complete vertex by adding all the useful attributes 15.272 +void Mesh::vertex(float x, float y, float z) 15.273 +{ 15.274 + cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f); 15.275 + vattr[MESH_ATTR_VERTEX].data_valid = true; 15.276 + vattr[MESH_ATTR_VERTEX].nelem = 3; 15.277 + 15.278 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.279 + if(vattr[i].data_valid) { 15.280 + for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) { 15.281 + vattr[i].data.push_back(cur_val[i][j]); 15.282 + } 15.283 + } 15.284 + vattr[i].vbo_valid = false; 15.285 + } 15.286 + 15.287 + if(idata_valid) { 15.288 + idata.clear(); 15.289 + } 15.290 + ibo_valid = idata_valid = false; 15.291 +} 15.292 + 15.293 +void Mesh::normal(float nx, float ny, float nz) 15.294 +{ 15.295 + cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f); 15.296 + vattr[MESH_ATTR_NORMAL].data_valid = true; 15.297 + vattr[MESH_ATTR_NORMAL].nelem = 3; 15.298 +} 15.299 + 15.300 +void Mesh::tangent(float tx, float ty, float tz) 15.301 +{ 15.302 + cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f); 15.303 + vattr[MESH_ATTR_TANGENT].data_valid = true; 15.304 + vattr[MESH_ATTR_TANGENT].nelem = 3; 15.305 +} 15.306 + 15.307 +void Mesh::texcoord(float u, float v, float w) 15.308 +{ 15.309 + cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f); 15.310 + vattr[MESH_ATTR_TEXCOORD].data_valid = true; 15.311 + vattr[MESH_ATTR_TEXCOORD].nelem = 3; 15.312 +} 15.313 + 15.314 +void Mesh::boneweights(float w1, float w2, float w3, float w4) 15.315 +{ 15.316 + cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4); 15.317 + vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true; 15.318 + vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4; 15.319 +} 15.320 + 15.321 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4) 15.322 +{ 15.323 + cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4); 15.324 + vattr[MESH_ATTR_BONEIDX].data_valid = true; 15.325 + vattr[MESH_ATTR_BONEIDX].nelem = 4; 15.326 +} 15.327 + 15.328 +/// static function 15.329 +void Mesh::set_attrib_location(int attr, int loc) 15.330 +{ 15.331 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 15.332 + return; 15.333 + } 15.334 + Mesh::global_sdr_loc[attr] = loc; 15.335 +} 15.336 + 15.337 +/// static function 15.338 +int Mesh::get_attrib_location(int attr) 15.339 +{ 15.340 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 15.341 + return -1; 15.342 + } 15.343 + return Mesh::global_sdr_loc[attr]; 15.344 +} 15.345 + 15.346 +/// static function 15.347 +void Mesh::clear_attrib_locations() 15.348 +{ 15.349 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.350 + Mesh::global_sdr_loc[i] = -1; 15.351 + } 15.352 +} 15.353 + 15.354 +/// static function 15.355 +void Mesh::set_vis_vecsize(float sz) 15.356 +{ 15.357 + Mesh::vis_vecsize = sz; 15.358 +} 15.359 + 15.360 +float Mesh::get_vis_vecsize() 15.361 +{ 15.362 + return Mesh::vis_vecsize; 15.363 +} 15.364 + 15.365 +void Mesh::apply_xform(const Matrix4x4 &xform) 15.366 +{ 15.367 + Matrix4x4 dir_xform = xform; 15.368 + dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f; 15.369 + dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f; 15.370 + dir_xform[3][3] = 1.0f; 15.371 + 15.372 + apply_xform(xform, dir_xform); 15.373 +} 15.374 + 15.375 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform) 15.376 +{ 15.377 + for(unsigned int i=0; i<nverts; i++) { 15.378 + Vector4 v = get_attrib(MESH_ATTR_VERTEX, i); 15.379 + set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform)); 15.380 + 15.381 + if(has_attrib(MESH_ATTR_NORMAL)) { 15.382 + Vector3 n = get_attrib(MESH_ATTR_NORMAL, i); 15.383 + set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform)); 15.384 + } 15.385 + if(has_attrib(MESH_ATTR_TANGENT)) { 15.386 + Vector3 t = get_attrib(MESH_ATTR_TANGENT, i); 15.387 + set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform)); 15.388 + } 15.389 + } 15.390 +} 15.391 + 15.392 +/* 15.393 +int Mesh::add_bone(XFormNode *bone) 15.394 +{ 15.395 + int idx = bones.size(); 15.396 + bones.push_back(bone); 15.397 + return idx; 15.398 +} 15.399 + 15.400 +const XFormNode *Mesh::get_bone(int idx) const 15.401 +{ 15.402 + if(idx < 0 || idx >= (int)bones.size()) { 15.403 + return 0; 15.404 + } 15.405 + return bones[idx]; 15.406 +} 15.407 + 15.408 +int Mesh::get_bones_count() const 15.409 +{ 15.410 + return (int)bones.size(); 15.411 +} 15.412 +*/ 15.413 + 15.414 +void Mesh::draw() const 15.415 +{ 15.416 + const ShaderProg *cur_sdr = get_current_shader(); 15.417 +#ifdef GL_ES_VERSION_2_0 15.418 + if(!cur_sdr) { 15.419 + fprintf(stderr, "%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__); 15.420 + return; 15.421 + } 15.422 +#endif 15.423 + 15.424 + ((Mesh*)this)->update_buffers(); 15.425 + 15.426 + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { 15.427 + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); 15.428 + return; 15.429 + } 15.430 + 15.431 + if(cur_sdr) { 15.432 + // rendering with shaders 15.433 + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { 15.434 + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); 15.435 + return; 15.436 + } 15.437 + 15.438 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.439 + int loc = global_sdr_loc[i]; 15.440 + if(loc >= 0 && vattr[i].vbo_valid) { 15.441 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 15.442 + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); 15.443 + glEnableVertexAttribArray(loc); 15.444 + } 15.445 + } 15.446 + } else { 15.447 +#ifndef GL_ES_VERSION_2_0 15.448 + // rendering with fixed-function (not available in GLES2) 15.449 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo); 15.450 + glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0); 15.451 + glEnableClientState(GL_VERTEX_ARRAY); 15.452 + 15.453 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 15.454 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo); 15.455 + glNormalPointer(GL_FLOAT, 0, 0); 15.456 + glEnableClientState(GL_NORMAL_ARRAY); 15.457 + } 15.458 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 15.459 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo); 15.460 + glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0); 15.461 + glEnableClientState(GL_TEXTURE_COORD_ARRAY); 15.462 + } 15.463 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 15.464 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo); 15.465 + glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0); 15.466 + glEnableClientState(GL_COLOR_ARRAY); 15.467 + } 15.468 +#endif 15.469 + } 15.470 + glBindBuffer(GL_ARRAY_BUFFER, 0); 15.471 + 15.472 + if(ibo_valid) { 15.473 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 15.474 + glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0); 15.475 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 15.476 + } else { 15.477 + glDrawArrays(GL_TRIANGLES, 0, nverts); 15.478 + } 15.479 + 15.480 + if(cur_sdr) { 15.481 + // rendered with shaders 15.482 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.483 + int loc = global_sdr_loc[i]; 15.484 + if(loc >= 0 && vattr[i].vbo_valid) { 15.485 + glDisableVertexAttribArray(loc); 15.486 + } 15.487 + } 15.488 + } else { 15.489 +#ifndef GL_ES_VERSION_2_0 15.490 + // rendered with fixed-function 15.491 + glDisableClientState(GL_VERTEX_ARRAY); 15.492 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 15.493 + glDisableClientState(GL_NORMAL_ARRAY); 15.494 + } 15.495 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 15.496 + glDisableClientState(GL_TEXTURE_COORD_ARRAY); 15.497 + } 15.498 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 15.499 + glDisableClientState(GL_COLOR_ARRAY); 15.500 + } 15.501 +#endif 15.502 + } 15.503 +} 15.504 + 15.505 +void Mesh::draw_wire() const 15.506 +{ 15.507 + ((Mesh*)this)->update_wire_ibo(); 15.508 + 15.509 + if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) { 15.510 + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); 15.511 + return; 15.512 + } 15.513 + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { 15.514 + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); 15.515 + return; 15.516 + } 15.517 + 15.518 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.519 + int loc = global_sdr_loc[i]; 15.520 + if(loc >= 0 && vattr[i].vbo_valid) { 15.521 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 15.522 + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); 15.523 + glEnableVertexAttribArray(loc); 15.524 + } 15.525 + } 15.526 + glBindBuffer(GL_ARRAY_BUFFER, 0); 15.527 + 15.528 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 15.529 + glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0); 15.530 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 15.531 + 15.532 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.533 + int loc = global_sdr_loc[i]; 15.534 + if(loc >= 0 && vattr[i].vbo_valid) { 15.535 + glDisableVertexAttribArray(loc); 15.536 + } 15.537 + } 15.538 +} 15.539 + 15.540 +void Mesh::draw_vertices() const 15.541 +{ 15.542 + ((Mesh*)this)->update_buffers(); 15.543 + 15.544 + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { 15.545 + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); 15.546 + return; 15.547 + } 15.548 + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { 15.549 + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); 15.550 + return; 15.551 + } 15.552 + 15.553 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.554 + int loc = global_sdr_loc[i]; 15.555 + if(loc >= 0 && vattr[i].vbo_valid) { 15.556 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 15.557 + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); 15.558 + glEnableVertexAttribArray(loc); 15.559 + } 15.560 + } 15.561 + glBindBuffer(GL_ARRAY_BUFFER, 0); 15.562 + 15.563 + glDrawArrays(GL_POINTS, 0, nverts); 15.564 + 15.565 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.566 + int loc = global_sdr_loc[i]; 15.567 + if(loc >= 0 && vattr[i].vbo_valid) { 15.568 + glDisableVertexAttribArray(loc); 15.569 + } 15.570 + } 15.571 +} 15.572 + 15.573 +void Mesh::draw_normals() const 15.574 +{ 15.575 +#ifdef USE_OLDGL 15.576 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 15.577 + Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 15.578 + Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); 15.579 + 15.580 + if(!varr || !norm || vert_loc < 0) { 15.581 + return; 15.582 + } 15.583 + 15.584 + glBegin(GL_LINES); 15.585 + for(size_t i=0; i<nverts; i++) { 15.586 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 15.587 + Vector3 end = varr[i] + norm[i] * vis_vecsize; 15.588 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 15.589 + } 15.590 + glEnd(); 15.591 + 15.592 +#endif // USE_OLDGL 15.593 +} 15.594 + 15.595 +void Mesh::draw_tangents() const 15.596 +{ 15.597 +#ifdef USE_OLDGL 15.598 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 15.599 + Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 15.600 + Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT); 15.601 + 15.602 + if(!varr || !tang || vert_loc < 0) { 15.603 + return; 15.604 + } 15.605 + 15.606 + glBegin(GL_LINES); 15.607 + for(size_t i=0; i<nverts; i++) { 15.608 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 15.609 + Vector3 end = varr[i] + tang[i] * vis_vecsize; 15.610 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 15.611 + } 15.612 + glEnd(); 15.613 + 15.614 +#endif // USE_OLDGL 15.615 +} 15.616 + 15.617 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const 15.618 +{ 15.619 + if(!aabb_valid) { 15.620 + ((Mesh*)this)->calc_aabb(); 15.621 + } 15.622 + *vmin = aabb.min; 15.623 + *vmax = aabb.max; 15.624 +} 15.625 + 15.626 +const AABox &Mesh::get_aabbox() const 15.627 +{ 15.628 + if(!aabb_valid) { 15.629 + ((Mesh*)this)->calc_aabb(); 15.630 + } 15.631 + return aabb; 15.632 +} 15.633 + 15.634 +float Mesh::get_bsphere(Vector3 *center, float *rad) const 15.635 +{ 15.636 + if(!bsph_valid) { 15.637 + ((Mesh*)this)->calc_bsph(); 15.638 + } 15.639 + *center = bsph.center; 15.640 + *rad = bsph.radius; 15.641 + return bsph.radius; 15.642 +} 15.643 + 15.644 +const Sphere &Mesh::get_bsphere() const 15.645 +{ 15.646 + if(!bsph_valid) { 15.647 + ((Mesh*)this)->calc_bsph(); 15.648 + } 15.649 + return bsph; 15.650 +} 15.651 + 15.652 +/// static function 15.653 +void Mesh::set_intersect_mode(unsigned int mode) 15.654 +{ 15.655 + Mesh::intersect_mode = mode; 15.656 +} 15.657 + 15.658 +/// static function 15.659 +unsigned int Mesh::get_intersect_mode() 15.660 +{ 15.661 + return Mesh::intersect_mode; 15.662 +} 15.663 + 15.664 +/// static function 15.665 +void Mesh::set_vertex_select_distance(float dist) 15.666 +{ 15.667 + Mesh::vertex_sel_dist = dist; 15.668 +} 15.669 + 15.670 +/// static function 15.671 +float Mesh::get_vertex_select_distance() 15.672 +{ 15.673 + return Mesh::vertex_sel_dist; 15.674 +} 15.675 + 15.676 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const 15.677 +{ 15.678 + assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE)); 15.679 + 15.680 + const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 15.681 + const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); 15.682 + if(!varr) { 15.683 + return false; 15.684 + } 15.685 + const unsigned int *idxarr = get_index_data(); 15.686 + 15.687 + // first test with the bounding box 15.688 + AABox box; 15.689 + get_aabbox(&box.min, &box.max); 15.690 + if(!box.intersect(ray)) { 15.691 + return false; 15.692 + } 15.693 + 15.694 + HitPoint nearest_hit; 15.695 + nearest_hit.dist = FLT_MAX; 15.696 + nearest_hit.shape = 0; 15.697 + 15.698 + if(Mesh::intersect_mode & ISECT_VERTICES) { 15.699 + // we asked for "intersections" with the vertices of the mesh 15.700 + long nearest_vidx = -1; 15.701 + float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist; 15.702 + 15.703 + for(unsigned int i=0; i<nverts; i++) { 15.704 + 15.705 + if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) { 15.706 + continue; 15.707 + } 15.708 + 15.709 + // project the vertex onto the ray line 15.710 + float t = dot_product(varr[i] - ray.origin, ray.dir); 15.711 + Vector3 vproj = ray.origin + ray.dir * t; 15.712 + 15.713 + float dist_sq = (vproj - varr[i]).length_sq(); 15.714 + if(dist_sq < thres_sq) { 15.715 + if(!hit) { 15.716 + return true; 15.717 + } 15.718 + if(t < nearest_hit.dist) { 15.719 + nearest_hit.dist = t; 15.720 + nearest_vidx = i; 15.721 + } 15.722 + } 15.723 + } 15.724 + 15.725 + if(nearest_vidx != -1) { 15.726 + hitvert = varr[nearest_vidx]; 15.727 + nearest_hit.data = (void*)&hitvert; 15.728 + } 15.729 + 15.730 + } else { 15.731 + // regular intersection test with polygons 15.732 + 15.733 + for(unsigned int i=0; i<nfaces; i++) { 15.734 + Triangle face(i, varr, idxarr); 15.735 + 15.736 + // ignore back-facing polygons if the mode flags include ISECT_FRONT 15.737 + if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) { 15.738 + continue; 15.739 + } 15.740 + 15.741 + HitPoint fhit; 15.742 + if(face.intersect(ray, hit ? &fhit : 0)) { 15.743 + if(!hit) { 15.744 + return true; 15.745 + } 15.746 + if(fhit.dist < nearest_hit.dist) { 15.747 + nearest_hit = fhit; 15.748 + hitface = face; 15.749 + } 15.750 + } 15.751 + } 15.752 + } 15.753 + 15.754 + if(nearest_hit.shape) { 15.755 + if(hit) { 15.756 + *hit = nearest_hit; 15.757 + 15.758 + // if we are interested in the mesh and not the faces set obj to this 15.759 + if(Mesh::intersect_mode & ISECT_FACE) { 15.760 + hit->data = &hitface; 15.761 + } else if(Mesh::intersect_mode & ISECT_VERTICES) { 15.762 + hit->data = &hitvert; 15.763 + } else { 15.764 + hit->data = (void*)this; 15.765 + } 15.766 + } 15.767 + return true; 15.768 + } 15.769 + return false; 15.770 +} 15.771 + 15.772 + 15.773 +// ------ private member functions ------ 15.774 + 15.775 +void Mesh::calc_aabb() 15.776 +{ 15.777 + // the cast is to force calling the const version which doesn't invalidate 15.778 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 15.779 + return; 15.780 + } 15.781 + 15.782 + aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX); 15.783 + aabb.max = -aabb.min; 15.784 + 15.785 + for(unsigned int i=0; i<nverts; i++) { 15.786 + Vector4 v = get_attrib(MESH_ATTR_VERTEX, i); 15.787 + for(int j=0; j<3; j++) { 15.788 + if(v[j] < aabb.min[j]) { 15.789 + aabb.min[j] = v[j]; 15.790 + } 15.791 + if(v[j] > aabb.max[j]) { 15.792 + aabb.max[j] = v[j]; 15.793 + } 15.794 + } 15.795 + } 15.796 + aabb_valid = true; 15.797 +} 15.798 + 15.799 +void Mesh::calc_bsph() 15.800 +{ 15.801 + // the cast is to force calling the const version which doesn't invalidate 15.802 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 15.803 + return; 15.804 + } 15.805 + 15.806 + Vector3 v; 15.807 + bsph.center = Vector3(0, 0, 0); 15.808 + 15.809 + // first find the center 15.810 + for(unsigned int i=0; i<nverts; i++) { 15.811 + v = get_attrib(MESH_ATTR_VERTEX, i); 15.812 + bsph.center += v; 15.813 + } 15.814 + bsph.center /= (float)nverts; 15.815 + 15.816 + bsph.radius = 0.0f; 15.817 + for(unsigned int i=0; i<nverts; i++) { 15.818 + v = get_attrib(MESH_ATTR_VERTEX, i); 15.819 + float dist_sq = (v - bsph.center).length_sq(); 15.820 + if(dist_sq > bsph.radius) { 15.821 + bsph.radius = dist_sq; 15.822 + } 15.823 + } 15.824 + bsph.radius = sqrt(bsph.radius); 15.825 + 15.826 + bsph_valid = true; 15.827 +} 15.828 + 15.829 +void Mesh::update_buffers() 15.830 +{ 15.831 + for(int i=0; i<NUM_MESH_ATTR; i++) { 15.832 + if(has_attrib(i) && !vattr[i].vbo_valid) { 15.833 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 15.834 + glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW); 15.835 + vattr[i].vbo_valid = true; 15.836 + } 15.837 + } 15.838 + glBindBuffer(GL_ARRAY_BUFFER, 0); 15.839 + 15.840 + if(idata_valid && !ibo_valid) { 15.841 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 15.842 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW); 15.843 + ibo_valid = true; 15.844 + } 15.845 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 15.846 +} 15.847 + 15.848 +void Mesh::update_wire_ibo() 15.849 +{ 15.850 + update_buffers(); 15.851 + 15.852 + if(wire_ibo_valid) { 15.853 + return; 15.854 + } 15.855 + 15.856 + if(!wire_ibo) { 15.857 + glGenBuffers(1, &wire_ibo); 15.858 + } 15.859 + 15.860 + unsigned int *wire_idxarr = new unsigned int[nfaces * 6]; 15.861 + unsigned int *dest = wire_idxarr; 15.862 + 15.863 + if(ibo_valid) { 15.864 + // we're dealing with an indexed mesh 15.865 + const unsigned int *idxarr = ((const Mesh*)this)->get_index_data(); 15.866 + 15.867 + for(unsigned int i=0; i<nfaces; i++) { 15.868 + *dest++ = idxarr[0]; 15.869 + *dest++ = idxarr[1]; 15.870 + *dest++ = idxarr[1]; 15.871 + *dest++ = idxarr[2]; 15.872 + *dest++ = idxarr[2]; 15.873 + *dest++ = idxarr[0]; 15.874 + idxarr += 3; 15.875 + } 15.876 + } else { 15.877 + // not an indexed mesh ... 15.878 + for(unsigned int i=0; i<nfaces; i++) { 15.879 + int vidx = i * 3; 15.880 + *dest++ = vidx; 15.881 + *dest++ = vidx + 1; 15.882 + *dest++ = vidx + 1; 15.883 + *dest++ = vidx + 2; 15.884 + *dest++ = vidx + 2; 15.885 + *dest++ = vidx; 15.886 + } 15.887 + } 15.888 + 15.889 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 15.890 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW); 15.891 + delete [] wire_idxarr; 15.892 + wire_ibo_valid = true; 15.893 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 15.894 +} 15.895 + 15.896 + 15.897 +// ------ class Triangle ------ 15.898 +Triangle::Triangle() 15.899 +{ 15.900 + normal_valid = false; 15.901 + id = -1; 15.902 +} 15.903 + 15.904 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2) 15.905 +{ 15.906 + v[0] = v0; 15.907 + v[1] = v1; 15.908 + v[2] = v2; 15.909 + normal_valid = false; 15.910 + id = -1; 15.911 +} 15.912 + 15.913 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr) 15.914 +{ 15.915 + if(idxarr) { 15.916 + v[0] = varr[idxarr[n * 3]]; 15.917 + v[1] = varr[idxarr[n * 3 + 1]]; 15.918 + v[2] = varr[idxarr[n * 3 + 2]]; 15.919 + } else { 15.920 + v[0] = varr[n * 3]; 15.921 + v[1] = varr[n * 3 + 1]; 15.922 + v[2] = varr[n * 3 + 2]; 15.923 + } 15.924 + normal_valid = false; 15.925 + id = n; 15.926 +} 15.927 + 15.928 +void Triangle::calc_normal() 15.929 +{ 15.930 + normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized(); 15.931 + normal_valid = true; 15.932 +} 15.933 + 15.934 +const Vector3 &Triangle::get_normal() const 15.935 +{ 15.936 + if(!normal_valid) { 15.937 + ((Triangle*)this)->calc_normal(); 15.938 + } 15.939 + return normal; 15.940 +} 15.941 + 15.942 +void Triangle::transform(const Matrix4x4 &xform) 15.943 +{ 15.944 + v[0].transform(xform); 15.945 + v[1].transform(xform); 15.946 + v[2].transform(xform); 15.947 + normal_valid = false; 15.948 +} 15.949 + 15.950 +void Triangle::draw() const 15.951 +{ 15.952 + Vector3 n[3]; 15.953 + n[0] = get_normal(); 15.954 + n[1] = get_normal(); 15.955 + n[2] = get_normal(); 15.956 + 15.957 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 15.958 + int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL); 15.959 + 15.960 + glEnableVertexAttribArray(vloc); 15.961 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 15.962 + glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x); 15.963 + 15.964 + glDrawArrays(GL_TRIANGLES, 0, 3); 15.965 + 15.966 + glDisableVertexAttribArray(vloc); 15.967 + glDisableVertexAttribArray(nloc); 15.968 +} 15.969 + 15.970 +void Triangle::draw_wire() const 15.971 +{ 15.972 + static const int idxarr[] = {0, 1, 1, 2, 2, 0}; 15.973 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 15.974 + 15.975 + glEnableVertexAttribArray(vloc); 15.976 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 15.977 + 15.978 + glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr); 15.979 + 15.980 + glDisableVertexAttribArray(vloc); 15.981 +} 15.982 + 15.983 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const 15.984 +{ 15.985 + Vector3 norm = get_normal(); 15.986 + 15.987 + float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm)); 15.988 + if(area_sq < 1e-5) { 15.989 + return Vector3(0, 0, 0); 15.990 + } 15.991 + 15.992 + float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm)); 15.993 + float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm)); 15.994 + float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm)); 15.995 + 15.996 + return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq); 15.997 +} 15.998 + 15.999 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const 15.1000 +{ 15.1001 + Vector3 normal = get_normal(); 15.1002 + 15.1003 + float ndotdir = dot_product(ray.dir, normal); 15.1004 + if(fabs(ndotdir) < 1e-4) { 15.1005 + return false; 15.1006 + } 15.1007 + 15.1008 + Vector3 vertdir = v[0] - ray.origin; 15.1009 + float t = dot_product(normal, vertdir) / ndotdir; 15.1010 + 15.1011 + Vector3 pos = ray.origin + ray.dir * t; 15.1012 + Vector3 bary = calc_barycentric(pos); 15.1013 + 15.1014 + if(bary.x + bary.y + bary.z > 1.00001) { 15.1015 + return false; 15.1016 + } 15.1017 + 15.1018 + if(hit) { 15.1019 + hit->dist = t; 15.1020 + hit->pos = ray.origin + ray.dir * t; 15.1021 + hit->normal = normal; 15.1022 + hit->data = (void*)this; 15.1023 + } 15.1024 + return true; 15.1025 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/src/mesh.h Sun Feb 15 05:14:20 2015 +0200 16.3 @@ -0,0 +1,209 @@ 16.4 +#ifndef MESH_H_ 16.5 +#define MESH_H_ 16.6 + 16.7 +#include <string> 16.8 +#include <vector> 16.9 +#include <vmath/vmath.h> 16.10 +#include "geom.h" 16.11 + 16.12 +enum { 16.13 + MESH_ATTR_VERTEX, 16.14 + MESH_ATTR_NORMAL, 16.15 + MESH_ATTR_TANGENT, 16.16 + MESH_ATTR_TEXCOORD, 16.17 + MESH_ATTR_COLOR, 16.18 + MESH_ATTR_BONEWEIGHTS, 16.19 + MESH_ATTR_BONEIDX, 16.20 + 16.21 + NUM_MESH_ATTR 16.22 +}; 16.23 + 16.24 +// intersection mode flags 16.25 +enum { 16.26 + ISECT_DEFAULT = 0, // default (whole mesh, all intersections) 16.27 + ISECT_FRONT = 1, // front-faces only 16.28 + ISECT_FACE = 2, // return intersected face pointer instead of mesh 16.29 + ISECT_VERTICES = 4 // return (?) TODO 16.30 +}; 16.31 + 16.32 + 16.33 +class Triangle { 16.34 +public: 16.35 + Vector3 v[3]; 16.36 + Vector3 normal; 16.37 + bool normal_valid; 16.38 + int id; 16.39 + 16.40 + Triangle(); 16.41 + Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2); 16.42 + Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0); 16.43 + 16.44 + /// calculate normal (quite expensive) 16.45 + void calc_normal(); 16.46 + const Vector3 &get_normal() const; 16.47 + 16.48 + void transform(const Matrix4x4 &xform); 16.49 + 16.50 + void draw() const; 16.51 + void draw_wire() const; 16.52 + 16.53 + /// calculate barycentric coordinates of a point 16.54 + Vector3 calc_barycentric(const Vector3 &pos) const; 16.55 + 16.56 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 16.57 +}; 16.58 + 16.59 + 16.60 +class Mesh { 16.61 +private: 16.62 + std::string name; 16.63 + unsigned int nverts, nfaces; 16.64 + 16.65 + // current value for each attribute for the immedate mode 16.66 + // interface. 16.67 + Vector4 cur_val[NUM_MESH_ATTR]; 16.68 + 16.69 + unsigned int buffer_objects[NUM_MESH_ATTR + 1]; 16.70 + 16.71 + // vertex attribute data and buffer objects 16.72 + struct { 16.73 + int nelem; // number of elements per attribute range: [1, 4] 16.74 + std::vector<float> data; 16.75 + unsigned int vbo; 16.76 + mutable bool vbo_valid; // if this is false, the vbo needs updating from the data 16.77 + mutable bool data_valid; // if this is false, the data needs to be pulled from the vbo 16.78 + //int sdr_loc; 16.79 + } vattr[NUM_MESH_ATTR]; 16.80 + 16.81 + static int global_sdr_loc[NUM_MESH_ATTR]; 16.82 + 16.83 + //std::vector<XFormNode*> bones; // bones affecting this mesh 16.84 + 16.85 + // index data and buffer object 16.86 + std::vector<unsigned int> idata; 16.87 + unsigned int ibo; 16.88 + mutable bool ibo_valid; 16.89 + mutable bool idata_valid; 16.90 + 16.91 + // index buffer object for wireframe rendering (constructed on demand) 16.92 + unsigned int wire_ibo; 16.93 + mutable bool wire_ibo_valid; 16.94 + 16.95 + // axis-aligned bounding box 16.96 + mutable AABox aabb; 16.97 + mutable bool aabb_valid; 16.98 + 16.99 + // bounding sphere 16.100 + mutable Sphere bsph; 16.101 + mutable bool bsph_valid; 16.102 + 16.103 + // keeps the last intersected face 16.104 + mutable Triangle hitface; 16.105 + // keeps the last intersected vertex position 16.106 + mutable Vector3 hitvert; 16.107 + 16.108 + void calc_aabb(); 16.109 + void calc_bsph(); 16.110 + 16.111 + static unsigned int intersect_mode; 16.112 + static float vertex_sel_dist; 16.113 + 16.114 + static float vis_vecsize; 16.115 + 16.116 + /// update the VBOs after data has changed (invalid vbo/ibo) 16.117 + void update_buffers(); 16.118 + /// construct/update the wireframe index buffer (called from draw_wire). 16.119 + void update_wire_ibo(); 16.120 + 16.121 + 16.122 +public: 16.123 + Mesh(); 16.124 + ~Mesh(); 16.125 + 16.126 + void set_name(const char *name); 16.127 + const char *get_name() const; 16.128 + 16.129 + bool has_attrib(int attr) const; 16.130 + 16.131 + // clears everything about this mesh, and returns to the newly constructed state 16.132 + void clear(); 16.133 + 16.134 + // access the vertex attribute data 16.135 + // if vdata == 0, space is just allocated 16.136 + float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo 16.137 + float *get_attrib_data(int attrib); // invalidates vbo 16.138 + const float *get_attrib_data(int attrib) const; 16.139 + 16.140 + // simple access to any particular attribute 16.141 + void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo 16.142 + Vector4 get_attrib(int attrib, int idx) const; 16.143 + 16.144 + // ... same for index data 16.145 + unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo 16.146 + unsigned int *get_index_data(); // invalidates ibo 16.147 + const unsigned int *get_index_data() const; 16.148 + 16.149 + void append(const Mesh &mesh); 16.150 + 16.151 + // immediate-mode style mesh construction interface 16.152 + void vertex(float x, float y, float z); 16.153 + void normal(float nx, float ny, float nz); 16.154 + void tangent(float tx, float ty, float tz); 16.155 + void texcoord(float u, float v, float w); 16.156 + void boneweights(float w1, float w2, float w3, float w4); 16.157 + void boneidx(int idx1, int idx2, int idx3, int idx4); 16.158 + 16.159 + /* apply a transformation to the vertices and its inverse-transpose 16.160 + * to the normals and tangents. 16.161 + */ 16.162 + void apply_xform(const Matrix4x4 &xform); 16.163 + void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform); 16.164 + 16.165 + // adds a bone and returns its index 16.166 + /*int add_bone(XFormNode *bone); 16.167 + const XFormNode *get_bone(int idx) const; 16.168 + int get_bones_count() const; 16.169 + */ 16.170 + 16.171 + // access the shader attribute locations 16.172 + static void set_attrib_location(int attr, int loc); 16.173 + static int get_attrib_location(int attr); 16.174 + static void clear_attrib_locations(); 16.175 + 16.176 + static void set_vis_vecsize(float sz); 16.177 + static float get_vis_vecsize(); 16.178 + 16.179 + void draw() const; 16.180 + void draw_wire() const; 16.181 + void draw_vertices() const; 16.182 + void draw_normals() const; 16.183 + void draw_tangents() const; 16.184 + 16.185 + /** get the bounding box in local space. The result will be cached, and subsequent 16.186 + * calls will return the same box. The cache gets invalidated by any functions that can affect 16.187 + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). 16.188 + * @{ */ 16.189 + void get_aabbox(Vector3 *vmin, Vector3 *vmax) const; 16.190 + const AABox &get_aabbox() const; 16.191 + /// @} 16.192 + 16.193 + /** get the bounding sphere in local space. The result will be cached, and subsequent 16.194 + * calls will return the same box. The cache gets invalidated by any functions that can affect 16.195 + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). 16.196 + * @{ */ 16.197 + float get_bsphere(Vector3 *center, float *rad) const; 16.198 + const Sphere &get_bsphere() const; 16.199 + 16.200 + static void set_intersect_mode(unsigned int mode); 16.201 + static unsigned int get_intersect_mode(); 16.202 + static void set_vertex_select_distance(float dist); 16.203 + static float get_vertex_select_distance(); 16.204 + 16.205 + /** Find the intersection between the mesh and a ray. 16.206 + * XXX Brute force at the moment, not intended to be used for anything other than picking in tools. 16.207 + * If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it! 16.208 + */ 16.209 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 16.210 +}; 16.211 + 16.212 +#endif // MESH_H_
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/src/objfile.c Sun Feb 15 05:14:20 2015 +0200 17.3 @@ -0,0 +1,308 @@ 17.4 +/* version 2: does not crash when there are no texture coordinates or normals */ 17.5 +#include <stdio.h> 17.6 +#include <stdlib.h> 17.7 +#include <string.h> 17.8 +#include <errno.h> 17.9 +#include <limits.h> 17.10 +#include <ctype.h> 17.11 +#include "objfile.h" 17.12 + 17.13 +#define INVALID_IDX INT_MIN 17.14 + 17.15 +struct objfile { 17.16 + float *verts, *normals, *texcoords; 17.17 + int num_faces; 17.18 +}; 17.19 + 17.20 +struct vec3 { 17.21 + float x, y, z; 17.22 +}; 17.23 + 17.24 +struct face { 17.25 + int vidx[4]; 17.26 + int nidx[4]; 17.27 + int tidx[4]; 17.28 +}; 17.29 + 17.30 +static int objf_read(struct objfile *obj, FILE *fp, const char *fname); 17.31 +static int count_elem(FILE *fp, const char *elem); 17.32 +static char *strip(char *s); 17.33 +static int mkface(char *line, struct face *face); 17.34 +static int parse_face(char *s, int *vidx, int *nidx, int *tidx); 17.35 +static int is_int(const char *str); 17.36 + 17.37 + 17.38 +struct objfile *objf_load(const char *fname) 17.39 +{ 17.40 + FILE *fp; 17.41 + struct objfile *obj; 17.42 + 17.43 + if(!(fp = fopen(fname, "rb"))) { 17.44 + fprintf(stderr, "objf_load: failed to open file: %s: %s\n", fname, strerror(errno)); 17.45 + return 0; 17.46 + } 17.47 + 17.48 + if(!(obj = malloc(sizeof *obj))) { 17.49 + perror("failed to allocate objfile structure\n"); 17.50 + fclose(fp); 17.51 + return 0; 17.52 + } 17.53 + 17.54 + if(objf_read(obj, fp, fname) == -1) { 17.55 + free(obj); 17.56 + obj = 0; 17.57 + } 17.58 + fclose(fp); 17.59 + return obj; 17.60 +} 17.61 + 17.62 +void objf_free(struct objfile *obj) 17.63 +{ 17.64 + if(obj) { 17.65 + free(obj->verts); 17.66 + free(obj->normals); 17.67 + free(obj->texcoords); 17.68 + free(obj); 17.69 + } 17.70 +} 17.71 + 17.72 +int objf_vertex_count(struct objfile *obj) 17.73 +{ 17.74 + return obj->num_faces * 3; 17.75 +} 17.76 + 17.77 +int objf_face_count(struct objfile *obj) 17.78 +{ 17.79 + return obj->num_faces; 17.80 +} 17.81 + 17.82 +float *objf_vertices(struct objfile *obj) 17.83 +{ 17.84 + return obj->verts; 17.85 +} 17.86 + 17.87 +float *objf_normals(struct objfile *obj) 17.88 +{ 17.89 + return obj->normals; 17.90 +} 17.91 + 17.92 +float *objf_texcoords(struct objfile *obj) 17.93 +{ 17.94 + return obj->texcoords; 17.95 +} 17.96 + 17.97 + 17.98 +float *objf_vertex(struct objfile *obj, int idx) 17.99 +{ 17.100 + return obj->verts + idx * 3; 17.101 +} 17.102 + 17.103 +float *objf_normal(struct objfile *obj, int idx) 17.104 +{ 17.105 + return obj->normals + idx * 3; 17.106 +} 17.107 + 17.108 +float *objf_texcoord(struct objfile *obj, int idx) 17.109 +{ 17.110 + return obj->texcoords + idx * 2; 17.111 +} 17.112 + 17.113 +static int objf_read(struct objfile *obj, FILE *fp, const char *fname) 17.114 +{ 17.115 + int i, j, res = -1; 17.116 + int vcount, ncount, tcount, fcount; 17.117 + int num_verts; 17.118 + struct vec3 *varr, *narr, *tarr; 17.119 + struct vec3 *vptr, *nptr, *tptr; 17.120 + struct vec3 dummy_vec = {0, 0, 0}; 17.121 + struct face *faces, *fptr; 17.122 + float *vdest, *ndest, *tdest; 17.123 + char buf[512]; 17.124 + 17.125 + vcount = count_elem(fp, "v"); 17.126 + rewind(fp); 17.127 + ncount = count_elem(fp, "vn"); 17.128 + rewind(fp); 17.129 + tcount = count_elem(fp, "vt"); 17.130 + rewind(fp); 17.131 + fcount = count_elem(fp, "f"); 17.132 + rewind(fp); 17.133 + 17.134 + obj->num_faces = fcount; 17.135 + 17.136 + if(!vcount || !fcount) { 17.137 + fprintf(stderr, "invalid or corrupted obj file: %s\n", fname); 17.138 + return -1; 17.139 + } 17.140 + 17.141 + printf("Reading obj file: %s (%d vertices, %d faces)\n", fname, vcount, fcount); 17.142 + 17.143 + vptr = varr = malloc(vcount * sizeof *varr); 17.144 + nptr = narr = ncount ? malloc(ncount * sizeof *narr) : &dummy_vec; 17.145 + tptr = tarr = tcount ? malloc(tcount * sizeof *tarr) : &dummy_vec; 17.146 + fptr = faces = malloc(fcount * sizeof *faces); 17.147 + 17.148 + if(!varr || !narr || !tarr || !faces) { 17.149 + perror("can't allocate enough memory for the geometry"); 17.150 + goto cleanup; 17.151 + } 17.152 + 17.153 + while(fgets(buf, sizeof buf, fp)) { 17.154 + char *line; 17.155 + 17.156 + if(!(line = strip(buf)) || *line == '#') { 17.157 + continue; /* ignore empty lines and comments */ 17.158 + } 17.159 + 17.160 + if(sscanf(line, "v %f %f %f", &vptr->x, &vptr->y, &vptr->z) == 3) { 17.161 + vptr++; 17.162 + } else if(sscanf(line, "vn %f %f %f", &nptr->x, &nptr->y, &nptr->z) == 3) { 17.163 + nptr++; 17.164 + } else if(sscanf(line, "vt %f %f", &tptr->x, &tptr->y) == 2) { 17.165 + tptr++; 17.166 + } else if(mkface(line, fptr) == 0) { 17.167 + fptr++; 17.168 + } 17.169 + } 17.170 + 17.171 + /* now go forth and create the straight-up 3-vert-per-face vertex arrays */ 17.172 + num_verts = obj->num_faces * 3; 17.173 + 17.174 + vdest = obj->verts = malloc(num_verts * 3 * sizeof *obj->verts); 17.175 + ndest = obj->normals = malloc(num_verts * 3 * sizeof *obj->normals); 17.176 + tdest = obj->texcoords = malloc(num_verts * 2 * sizeof *obj->texcoords); 17.177 + 17.178 + if(!obj->verts || !obj->normals || !obj->texcoords) { 17.179 + free(obj->verts); 17.180 + free(obj->normals); 17.181 + goto cleanup; 17.182 + } 17.183 + 17.184 + /* for all faces */ 17.185 + for(i=0; i<fcount; i++) { 17.186 + /* for the 3 vertices of each face */ 17.187 + for(j=0; j<3; j++) { 17.188 + *vdest++ = varr[faces[i].vidx[j]].x; 17.189 + *vdest++ = varr[faces[i].vidx[j]].y; 17.190 + *vdest++ = varr[faces[i].vidx[j]].z; 17.191 + 17.192 + *ndest++ = narr[faces[i].nidx[j]].x; 17.193 + *ndest++ = narr[faces[i].nidx[j]].y; 17.194 + *ndest++ = narr[faces[i].nidx[j]].z; 17.195 + 17.196 + *tdest++ = tarr[faces[i].tidx[j]].x; 17.197 + *tdest++ = tarr[faces[i].tidx[j]].y; 17.198 + } 17.199 + } 17.200 + res = 0; /* success */ 17.201 + 17.202 +cleanup: 17.203 + free(varr); 17.204 + if(narr != &dummy_vec) { 17.205 + free(narr); 17.206 + } 17.207 + if(tarr != &dummy_vec) { 17.208 + free(tarr); 17.209 + } 17.210 + free(faces); 17.211 + return res; 17.212 +} 17.213 + 17.214 +static int count_elem(FILE *fp, const char *elem) 17.215 +{ 17.216 + int count = 0; 17.217 + char buf[512]; 17.218 + 17.219 + while(fgets(buf, sizeof buf, fp)) { 17.220 + if(buf[0] == elem[0] && (!elem[1] || buf[1] == elem[1])) { 17.221 + count++; 17.222 + } 17.223 + } 17.224 + return count; 17.225 +} 17.226 + 17.227 + 17.228 +static char *strip(char *s) 17.229 +{ 17.230 + while(*s && isspace(*s)) { 17.231 + s++; 17.232 + } 17.233 + return s; 17.234 +} 17.235 + 17.236 +static int mkface(char *s, struct face *face) 17.237 +{ 17.238 + int nverts; 17.239 + 17.240 + if(s[0] != 'f') { 17.241 + return -1; 17.242 + } 17.243 + 17.244 + if((nverts = parse_face(s + 2, face->vidx, face->nidx, face->tidx)) == -1) { 17.245 + return -1; 17.246 + } 17.247 + if(nverts > 3) { 17.248 + fprintf(stderr, "warning face with more than 3 vertices found\n"); 17.249 + } 17.250 + return 0; 17.251 +} 17.252 + 17.253 +#define SEP " \t\v\n\r" 17.254 +/* returns the number of vertices on this face, or -1 on error. */ 17.255 +static int parse_face(char *s, int *vidx, int *nidx, int *tidx) 17.256 +{ 17.257 + int i, num_verts = 0; 17.258 + char *tok[] = {0, 0, 0, 0}; 17.259 + char *subtok; 17.260 + 17.261 + for(i=0; i<4; i++) { 17.262 + if((!(tok[i] = strtok(i == 0 ? s : 0, SEP)) || !is_int(tok[i]))) { 17.263 + if(i < 3) return -1; 17.264 + } else { 17.265 + num_verts++; 17.266 + } 17.267 + } 17.268 + 17.269 + for(i=0; i<4; i++) { 17.270 + subtok = tok[i]; 17.271 + if(!subtok || !*subtok || !is_int(subtok)) { 17.272 + if(i < 3) { 17.273 + return -1; 17.274 + } 17.275 + vidx[i] = INVALID_IDX; 17.276 + } else { 17.277 + vidx[i] = atoi(subtok); 17.278 + if(vidx[i] > 0) vidx[i]--; /* convert to 0-based */ 17.279 + } 17.280 + 17.281 + while(subtok && *subtok && *subtok != '/') { 17.282 + subtok++; 17.283 + } 17.284 + if(subtok && *subtok && *++subtok && is_int(subtok)) { 17.285 + tidx[i] = atoi(subtok); 17.286 + if(tidx[i] > 0) tidx[i]--; /* convert to 0-based */ 17.287 + } else { 17.288 + tidx[i] = 0; 17.289 + } 17.290 + 17.291 + while(subtok && *subtok && *subtok != '/') { 17.292 + subtok++; 17.293 + } 17.294 + if(subtok && *subtok && *++subtok && is_int(subtok)) { 17.295 + nidx[i] = atoi(subtok); 17.296 + if(nidx[i] > 0) nidx[i]--; /* convert to 0-based */ 17.297 + } else { 17.298 + nidx[i] = 0; 17.299 + } 17.300 + } 17.301 + 17.302 + return num_verts; 17.303 +} 17.304 + 17.305 + 17.306 +static int is_int(const char *str) 17.307 +{ 17.308 + return isdigit(str[0]) || 17.309 + (str[0] == '-' && isdigit(str[1])) || 17.310 + (str[0] == '+' && isdigit(str[1])); 17.311 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/src/objfile.h Sun Feb 15 05:14:20 2015 +0200 18.3 @@ -0,0 +1,29 @@ 18.4 +#ifndef OBJFILE_H_ 18.5 +#define OBJFILE_H_ 18.6 + 18.7 +struct objfile; 18.8 + 18.9 +#ifdef __cplusplus 18.10 +extern "C" { 18.11 +#endif 18.12 + 18.13 +struct objfile *objf_load(const char *fname); 18.14 +void objf_free(struct objfile *obj); 18.15 + 18.16 +int objf_vertex_count(struct objfile *obj); 18.17 +int objf_face_count(struct objfile *obj); 18.18 + 18.19 +float *objf_vertices(struct objfile *obj); 18.20 +float *objf_normals(struct objfile *obj); 18.21 +float *objf_texcoords(struct objfile *obj); 18.22 + 18.23 +float *objf_vertex(struct objfile *obj, int idx); 18.24 +float *objf_normal(struct objfile *obj, int idx); 18.25 +float *objf_texcoord(struct objfile *obj, int idx); 18.26 + 18.27 + 18.28 +#ifdef __cplusplus 18.29 +} 18.30 +#endif 18.31 + 18.32 +#endif /* OBJFILE_H_ */
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/src/opengl.cc Sun Feb 15 05:14:20 2015 +0200 19.3 @@ -0,0 +1,7 @@ 19.4 +#include "opengl.h" 19.5 + 19.6 +bool init_opengl() 19.7 +{ 19.8 + glewInit(); 19.9 + return true; 19.10 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/src/opengl.h Sun Feb 15 05:14:20 2015 +0200 20.3 @@ -0,0 +1,8 @@ 20.4 +#ifndef OPENGL_H_ 20.5 +#define OPENGL_H_ 20.6 + 20.7 +#include <GL/glew.h> 20.8 + 20.9 +bool init_opengl(); 20.10 + 20.11 +#endif // OPENGL_H_
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/src/shader.cc Sun Feb 15 05:14:20 2015 +0200 21.3 @@ -0,0 +1,679 @@ 21.4 +#include <stdio.h> 21.5 +#include <string.h> 21.6 +#include <stdarg.h> 21.7 +#include <errno.h> 21.8 +#include "opengl.h" 21.9 +#include "shader.h" 21.10 +#include "mesh.h" 21.11 + 21.12 +#ifdef _MSC_VER 21.13 +#include <malloc.h> 21.14 +#else 21.15 +#include <alloca.h> 21.16 +#endif 21.17 + 21.18 +#ifdef __GLEW_H__ 21.19 +#define HAVE_GEOMETRY_SHADER 21.20 +#define HAVE_TESSELATION_SHADER 21.21 +#endif 21.22 + 21.23 +static std::string read_source(const char *fname); 21.24 +static void bind_standard_attr(const ShaderProg *prog); 21.25 + 21.26 +ShaderProg *ShaderProg::current; 21.27 + 21.28 +void bind_shader(const ShaderProg *sdr) 21.29 +{ 21.30 + if(sdr) { 21.31 + sdr->bind(); 21.32 + } else { 21.33 +#ifndef GL_ES_VERSION_2_0 21.34 + glUseProgram(0); 21.35 + ShaderProg::current = 0; 21.36 +#endif 21.37 + } 21.38 +} 21.39 + 21.40 +const ShaderProg *get_current_shader() 21.41 +{ 21.42 + return ShaderProg::current; 21.43 +} 21.44 + 21.45 +Shader::Shader() 21.46 +{ 21.47 + sdr = type = 0; 21.48 +} 21.49 + 21.50 +Shader::~Shader() 21.51 +{ 21.52 + destroy(); 21.53 +} 21.54 + 21.55 +unsigned int Shader::get_id() const 21.56 +{ 21.57 + return sdr; 21.58 +} 21.59 + 21.60 +void Shader::set_name(const char *name) 21.61 +{ 21.62 + this->name = std::string(name); 21.63 +} 21.64 + 21.65 +const char *Shader::get_name() const 21.66 +{ 21.67 + return name.c_str(); 21.68 +} 21.69 + 21.70 +bool Shader::create(const char *src, unsigned int type) 21.71 +{ 21.72 +#if !GL_ES_VERSION_2_0 21.73 + const char *src_arr[] = {src}; 21.74 +#else 21.75 + const char *src_arr[] = { "precision mediump float; ", src }; 21.76 +#endif 21.77 + 21.78 + // keep a copy of the source code 21.79 + this->src = std::string(src); 21.80 + 21.81 + if(!sdr) { 21.82 + sdr = glCreateShader(type); 21.83 + } 21.84 + 21.85 + printf("compiling shader: %s... ", name.c_str()); 21.86 + 21.87 + glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0); 21.88 + glCompileShader(sdr); 21.89 + 21.90 + int status; 21.91 + glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); 21.92 + 21.93 + printf(status ? "success\n" : "failed\n"); 21.94 + 21.95 + int info_len; 21.96 + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); 21.97 + if(info_len > 1) { 21.98 + char *buf = (char*)alloca(info_len); 21.99 + glGetShaderInfoLog(sdr, info_len, 0, buf); 21.100 + buf[info_len - 1] = 0; 21.101 + 21.102 + if(status) { 21.103 + printf("%s\n", buf); 21.104 + } else { 21.105 + fprintf(stderr, "%s\n", buf); 21.106 + } 21.107 + } 21.108 + 21.109 + return status == GL_TRUE; 21.110 +} 21.111 + 21.112 +void Shader::destroy() 21.113 +{ 21.114 + if(sdr) { 21.115 + glDeleteShader(sdr); 21.116 + } 21.117 + sdr = type = 0; 21.118 + 21.119 + src.clear(); 21.120 + name.clear(); 21.121 +} 21.122 + 21.123 +static std::string read_source(const char *fname) 21.124 +{ 21.125 + FILE *fp; 21.126 + 21.127 + if(!(fp = fopen(fname, "rb"))) { 21.128 + fprintf(stderr, "failed to load shader: %s: %s\n", fname, strerror(errno)); 21.129 + return std::string(); 21.130 + } 21.131 + 21.132 + fseek(fp, 0, SEEK_END); 21.133 + long sz = ftell(fp); 21.134 + rewind(fp); 21.135 + 21.136 + char *src = (char*)alloca(sz + 1); 21.137 + if(fread(src, 1, sz, fp) < (size_t)sz) { 21.138 + fprintf(stderr, "failed to load shader: %s: %s\n", fname, strerror(errno)); 21.139 + fclose(fp); 21.140 + delete [] src; 21.141 + return std::string(); 21.142 + } 21.143 + src[sz] = 0; 21.144 + fclose(fp); 21.145 + 21.146 + return std::string(src); 21.147 +} 21.148 + 21.149 +bool Shader::load(const char *fname, unsigned int type) 21.150 +{ 21.151 + std::string src = read_source(fname); 21.152 + if(src.empty()) { 21.153 + return false; 21.154 + } 21.155 + set_name(fname); 21.156 + return create(src.c_str(), type); 21.157 +} 21.158 + 21.159 +// ---- shader program ---- 21.160 +ShaderProg::ShaderProg() 21.161 +{ 21.162 + prog = 0; 21.163 + must_link = true; 21.164 +} 21.165 + 21.166 +ShaderProg::~ShaderProg() 21.167 +{ 21.168 + destroy(); 21.169 +} 21.170 + 21.171 +unsigned int ShaderProg::get_id() const 21.172 +{ 21.173 + return prog; 21.174 +} 21.175 + 21.176 +bool ShaderProg::create(const char *src, unsigned int type, ...) 21.177 +{ 21.178 + va_list ap; 21.179 + 21.180 + va_start(ap, type); 21.181 + bool res = create(src, type, ap); 21.182 + va_end(ap); 21.183 + 21.184 + return res; 21.185 +} 21.186 + 21.187 +bool ShaderProg::create(const char *src, unsigned int type, va_list ap) 21.188 +{ 21.189 + destroy(); 21.190 + prog = glCreateProgram(); 21.191 + 21.192 + while(src) { 21.193 + Shader *sdr = new Shader; 21.194 + if(!sdr->create(src, type)) { 21.195 + va_end(ap); 21.196 + return false; 21.197 + } 21.198 + add_shader(sdr); 21.199 + src = va_arg(ap, const char*); 21.200 + type = va_arg(ap, unsigned int); 21.201 + } 21.202 + 21.203 + return link(); 21.204 +} 21.205 + 21.206 +bool ShaderProg::create(const char *vsrc, const char *psrc) 21.207 +{ 21.208 + return create(VSDR(vsrc), PSDR(psrc), 0); 21.209 +} 21.210 + 21.211 +bool ShaderProg::create(Shader *sdr, ...) 21.212 +{ 21.213 + va_list ap; 21.214 + 21.215 + va_start(ap, sdr); 21.216 + bool res = create(sdr, ap); 21.217 + va_end(ap); 21.218 + 21.219 + return res; 21.220 +} 21.221 + 21.222 +bool ShaderProg::create(Shader *sdr, va_list ap) 21.223 +{ 21.224 + destroy(); 21.225 + prog = glCreateProgram(); 21.226 + 21.227 + while(sdr) { 21.228 + add_shader(sdr); 21.229 + sdr = va_arg(ap, Shader*); 21.230 + } 21.231 + return link(); 21.232 +} 21.233 + 21.234 +bool ShaderProg::create(Shader *vsdr, Shader *psdr) 21.235 +{ 21.236 + return create(vsdr, psdr, 0); 21.237 +} 21.238 + 21.239 +void ShaderProg::destroy() 21.240 +{ 21.241 + if(prog) { 21.242 + glDeleteProgram(prog); 21.243 + } 21.244 + prog = 0; 21.245 + 21.246 + shaders.clear(); 21.247 + // don't actually destroy the shaders, let the ShaderSet own them 21.248 +} 21.249 + 21.250 +bool ShaderProg::load(const char *fname, unsigned int type, ...) 21.251 +{ 21.252 + va_list ap; 21.253 + va_start(ap, type); 21.254 + bool res = load(fname, type, ap); 21.255 + va_end(ap); 21.256 + 21.257 + return res; 21.258 +} 21.259 + 21.260 +bool ShaderProg::load(const char *fname, unsigned int type, va_list ap) 21.261 +{ 21.262 + destroy(); 21.263 + prog = glCreateProgram(); 21.264 + 21.265 + while(fname) { 21.266 + Shader *sdr = new Shader; 21.267 + if(!sdr->load(fname, type)) { 21.268 + delete sdr; 21.269 + return false; 21.270 + } 21.271 + add_shader(sdr); 21.272 + 21.273 + if((fname = va_arg(ap, const char*))) { 21.274 + type = va_arg(ap, unsigned int); 21.275 + } 21.276 + } 21.277 + 21.278 + return link(); 21.279 +} 21.280 + 21.281 +bool ShaderProg::load(const char *vfname, const char *pfname) 21.282 +{ 21.283 + return load(VSDR(vfname), PSDR(pfname), 0); 21.284 +} 21.285 + 21.286 +void ShaderProg::add_shader(Shader *sdr) 21.287 +{ 21.288 + glAttachShader(prog, sdr->get_id()); 21.289 +} 21.290 + 21.291 +bool ShaderProg::link() const 21.292 +{ 21.293 + bind_standard_attr(this); 21.294 + 21.295 + printf("linking program ... "); 21.296 + glLinkProgram(prog); 21.297 + 21.298 + int status; 21.299 + glGetProgramiv(prog, GL_LINK_STATUS, &status); 21.300 + 21.301 + printf(status ? "success\n" : "failed\n"); 21.302 + 21.303 + int info_len; 21.304 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); 21.305 + if(info_len > 1) { 21.306 + char *buf = (char*)alloca(info_len); 21.307 + glGetProgramInfoLog(prog, info_len, 0, buf); 21.308 + buf[info_len - 1] = 0; 21.309 + 21.310 + if(status) { 21.311 + printf("%s\n", buf); 21.312 + } else { 21.313 + fprintf(stderr, "%s\n", buf); 21.314 + } 21.315 + } 21.316 + 21.317 + if(status) { 21.318 + must_link = false; 21.319 + //cache_state_uniforms(); 21.320 + return true; 21.321 + } 21.322 + return false; 21.323 +} 21.324 + 21.325 +void ShaderProg::bind() const 21.326 +{ 21.327 + if(must_link) { 21.328 + if(!link()) { 21.329 + return; 21.330 + } 21.331 + } 21.332 + glUseProgram(prog); 21.333 + ShaderProg::current = (ShaderProg*)this; 21.334 + 21.335 + //setup_state_uniforms(); 21.336 +} 21.337 + 21.338 + 21.339 +int ShaderProg::get_attrib_location(const char *name) const 21.340 +{ 21.341 + glUseProgram(prog); 21.342 + return glGetAttribLocation(prog, name); 21.343 +} 21.344 + 21.345 +void ShaderProg::set_attrib_location(const char *name, int loc) const 21.346 +{ 21.347 + glBindAttribLocation(prog, loc, name); 21.348 + must_link = true; 21.349 +} 21.350 + 21.351 +int ShaderProg::get_uniform_location(const char *name) const 21.352 +{ 21.353 + glUseProgram(prog); 21.354 + return glGetUniformLocation(prog, name); 21.355 +} 21.356 + 21.357 +bool ShaderProg::set_uniform(int loc, int val) const 21.358 +{ 21.359 + glUseProgram(prog); 21.360 + if(loc >= 0) { 21.361 + glUniform1i(loc, val); 21.362 + return true; 21.363 + } 21.364 + return false; 21.365 +} 21.366 + 21.367 +bool ShaderProg::set_uniform(int loc, float val) const 21.368 +{ 21.369 + glUseProgram(prog); 21.370 + if(loc >= 0) { 21.371 + glUniform1f(loc, val); 21.372 + return true; 21.373 + } 21.374 + return false; 21.375 +} 21.376 + 21.377 +bool ShaderProg::set_uniform(int loc, const Vector2 &v) const 21.378 +{ 21.379 + glUseProgram(prog); 21.380 + if(loc >= 0) { 21.381 + glUniform2f(loc, v.x, v.y); 21.382 + return true; 21.383 + } 21.384 + return false; 21.385 +} 21.386 + 21.387 +bool ShaderProg::set_uniform(int loc, const Vector3 &v) const 21.388 +{ 21.389 + glUseProgram(prog); 21.390 + if(loc >= 0) { 21.391 + glUniform3f(loc, v.x, v.y, v.z); 21.392 + return true; 21.393 + } 21.394 + return false; 21.395 +} 21.396 + 21.397 +bool ShaderProg::set_uniform(int loc, const Vector4 &v) const 21.398 +{ 21.399 + glUseProgram(prog); 21.400 + if(loc >= 0) { 21.401 + glUniform4f(loc, v.x, v.y, v.z, v.w); 21.402 + return true; 21.403 + } 21.404 + return false; 21.405 +} 21.406 + 21.407 +bool ShaderProg::set_uniform(int loc, const Matrix3x3 &m) const 21.408 +{ 21.409 + glUseProgram(prog); 21.410 + if(loc >= 0) { 21.411 + glUniformMatrix3fv(loc, 1, GL_TRUE, m[0]); 21.412 + return true; 21.413 + } 21.414 + return false; 21.415 +} 21.416 + 21.417 +bool ShaderProg::set_uniform(int loc, const Matrix4x4 &m) const 21.418 +{ 21.419 + glUseProgram(prog); 21.420 + if(loc >= 0) { 21.421 + glUniformMatrix4fv(loc, 1, GL_TRUE, m[0]); 21.422 + return true; 21.423 + } 21.424 + return false; 21.425 +} 21.426 + 21.427 + 21.428 +bool ShaderProg::set_uniform(const char *name, int val) const 21.429 +{ 21.430 + return set_uniform(get_uniform_location(name), val); 21.431 +} 21.432 + 21.433 +bool ShaderProg::set_uniform(const char *name, float val) const 21.434 +{ 21.435 + return set_uniform(get_uniform_location(name), val); 21.436 +} 21.437 + 21.438 +bool ShaderProg::set_uniform(const char *name, const Vector2 &v) const 21.439 +{ 21.440 + return set_uniform(get_uniform_location(name), v); 21.441 +} 21.442 + 21.443 +bool ShaderProg::set_uniform(const char *name, const Vector3 &v) const 21.444 +{ 21.445 + return set_uniform(get_uniform_location(name), v); 21.446 +} 21.447 + 21.448 +bool ShaderProg::set_uniform(const char *name, const Vector4 &v) const 21.449 +{ 21.450 + return set_uniform(get_uniform_location(name), v); 21.451 +} 21.452 + 21.453 +bool ShaderProg::set_uniform(const char *name, const Matrix3x3 &m) const 21.454 +{ 21.455 + return set_uniform(get_uniform_location(name), m); 21.456 +} 21.457 + 21.458 +bool ShaderProg::set_uniform(const char *name, const Matrix4x4 &m) const 21.459 +{ 21.460 + return set_uniform(get_uniform_location(name), m); 21.461 +} 21.462 + 21.463 +/* 21.464 +static StType unist_type(GLenum type) 21.465 +{ 21.466 + switch(type) { 21.467 + case GL_FLOAT: 21.468 + return ST_FLOAT; 21.469 + case GL_FLOAT_VEC2: 21.470 + return ST_FLOAT2; 21.471 + case GL_FLOAT_VEC3: 21.472 + return ST_FLOAT3; 21.473 + case GL_FLOAT_VEC4: 21.474 + return ST_FLOAT4; 21.475 + case GL_INT: 21.476 + case GL_SAMPLER_2D: 21.477 + case GL_SAMPLER_CUBE: 21.478 +#if !GL_ES_VERSION_2_0 21.479 + case GL_SAMPLER_1D: 21.480 + case GL_SAMPLER_3D: 21.481 + case GL_SAMPLER_1D_SHADOW: 21.482 + case GL_SAMPLER_2D_SHADOW: 21.483 +#endif 21.484 + return ST_INT; 21.485 + case GL_INT_VEC2: 21.486 + return ST_INT2; 21.487 + case GL_INT_VEC3: 21.488 + return ST_INT3; 21.489 + case GL_INT_VEC4: 21.490 + return ST_INT4; 21.491 + case GL_FLOAT_MAT3: 21.492 + return ST_MATRIX3; 21.493 + case GL_FLOAT_MAT4: 21.494 + return ST_MATRIX4; 21.495 + default: 21.496 + break; 21.497 + } 21.498 + return ST_UNKNOWN; 21.499 +} 21.500 + 21.501 +void ShaderProg::cache_state_uniforms() const 21.502 +{ 21.503 + if(!glIsProgram(prog)) { 21.504 + return; 21.505 + } 21.506 + 21.507 + int num_uni; 21.508 + glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni); 21.509 + 21.510 + char name[256]; 21.511 + for(int i=0; i<num_uni; i++) { 21.512 + GLint sz; 21.513 + GLenum type; 21.514 + glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name); 21.515 + 21.516 + if(strstr(name, "st_") == name) { 21.517 + StateLocCache s; 21.518 + s.sidx = add_unistate(name, unist_type(type)); 21.519 + s.loc = glGetUniformLocation(prog, name); 21.520 + stloc_cache.push_back(s); 21.521 + } 21.522 + } 21.523 +} 21.524 + 21.525 +void ShaderProg::setup_state_uniforms() const 21.526 +{ 21.527 + for(size_t i=0; i<stloc_cache.size(); i++) { 21.528 + setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc); 21.529 + } 21.530 +} 21.531 +*/ 21.532 + 21.533 +// Static functions to use with ShaderSet 21.534 +Shader *Shader::create_shader() 21.535 +{ 21.536 + return new Shader; 21.537 +} 21.538 + 21.539 +bool Shader::load_shader(Shader *sdr, const char *fname) 21.540 +{ 21.541 + std::string src = read_source(fname); 21.542 + if(src.empty()) { 21.543 + return false; 21.544 + } 21.545 + 21.546 + sdr->src = src; 21.547 + return true; 21.548 +} 21.549 + 21.550 +bool Shader::done_shader(Shader *sdr, unsigned int type) 21.551 +{ 21.552 + return sdr->create(sdr->src.c_str(), type); 21.553 +} 21.554 + 21.555 +/* 21.556 +static bool done_vertex_shader(Shader *sdr) 21.557 +{ 21.558 + return Shader::done_shader(sdr, GL_VERTEX_SHADER); 21.559 +} 21.560 + 21.561 +static bool done_pixel_shader(Shader *sdr) 21.562 +{ 21.563 + return Shader::done_shader(sdr, GL_FRAGMENT_SHADER); 21.564 +} 21.565 + 21.566 +#ifdef HAVE_GEOMETRY_SHADER 21.567 +static bool done_geom_shader(Shader *sdr) 21.568 +{ 21.569 + return Shader::done_shader(sdr, GL_GEOMETRY_SHADER); 21.570 +} 21.571 +#endif 21.572 + 21.573 +#ifdef HAVE_TESSELATION_SHADER 21.574 +static bool done_tc_shader(Shader *sdr) 21.575 +{ 21.576 + return Shader::done_shader(sdr, GL_TESS_CONTROL_SHADER); 21.577 +} 21.578 + 21.579 +static bool done_te_shader(Shader *sdr) 21.580 +{ 21.581 + return Shader::done_shader(sdr, GL_TESS_EVALUATION_SHADER); 21.582 +} 21.583 +#endif 21.584 + 21.585 +void Shader::destroy_shader(Shader *sdr) 21.586 +{ 21.587 + delete sdr; 21.588 +} 21.589 + 21.590 +// ---- ShaderSet ---- 21.591 + 21.592 +ShaderSet::ShaderSet(unsigned int type) 21.593 + : DataSet<Shader*>(Shader::create_shader, Shader::load_shader, 0, Shader::destroy_shader) 21.594 +{ 21.595 + switch(type) { 21.596 + case GL_VERTEX_SHADER: 21.597 + done = done_vertex_shader; 21.598 + break; 21.599 + 21.600 + case GL_FRAGMENT_SHADER: 21.601 + done = done_pixel_shader; 21.602 + break; 21.603 + 21.604 +#ifdef HAVE_GEOMETRY_SHADER 21.605 + case GL_GEOMETRY_SHADER: 21.606 + done = done_geom_shader; 21.607 + break; 21.608 +#endif 21.609 + 21.610 +#ifdef HAVE_TESSELATION_SHADER 21.611 + case GL_TESS_CONTROL_SHADER: 21.612 + done = done_tc_shader; 21.613 + break; 21.614 + 21.615 + case GL_TESS_EVALUATION_SHADER: 21.616 + done = done_te_shader; 21.617 + break; 21.618 +#endif 21.619 + 21.620 + default: 21.621 + fprintf(stderr, "ShaderSet constructed with invalid shader type!\n"); 21.622 + } 21.623 +} 21.624 +*/ 21.625 + 21.626 +static struct { const char *name; int loc; } attr_loc[] = { 21.627 + {"attr_vertex", MESH_ATTR_VERTEX}, 21.628 + {"attr_normal", MESH_ATTR_NORMAL}, 21.629 + {"attr_tangent", MESH_ATTR_TANGENT}, 21.630 + {"attr_texcoord", MESH_ATTR_TEXCOORD}, 21.631 + {"attr_color", MESH_ATTR_COLOR}, 21.632 + {"attr_boneweights", MESH_ATTR_BONEWEIGHTS}, 21.633 + {"attr_boneidx", MESH_ATTR_BONEIDX} 21.634 +}; 21.635 + 21.636 +static void bind_standard_attr(const ShaderProg *prog) 21.637 +{ 21.638 + // we must link once to find out which are the active attributes 21.639 + glLinkProgram(prog->get_id()); 21.640 + 21.641 + int num_attr; 21.642 + glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr); 21.643 + 21.644 + char name[256]; 21.645 + for(int i=0; i<num_attr; i++) { 21.646 + GLint sz; 21.647 + GLenum type; 21.648 + glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name); 21.649 + 21.650 + for(int j=0; j<(int)(sizeof attr_loc / sizeof *attr_loc); j++) { 21.651 + if(strcmp(name, attr_loc[j].name) == 0) { 21.652 + prog->set_attrib_location(name, attr_loc[j].loc); 21.653 + } 21.654 + } 21.655 + } 21.656 +} 21.657 + 21.658 + 21.659 +/* 21.660 +static const char *strtype(unsigned int type) 21.661 +{ 21.662 + switch(type) { 21.663 + case GL_VERTEX_SHADER: 21.664 + return "vertex"; 21.665 + case GL_FRAGMENT_SHADER: 21.666 + return "fragment"; 21.667 +#ifdef HAVE_GEOMETRY_SHADER 21.668 + case GL_GEOMETRY_SHADER: 21.669 + return "geometry"; 21.670 +#endif 21.671 +#ifdef HAVE_TESSELATION_SHADER 21.672 + case GL_TESS_CONTROL_SHADER: 21.673 + return "tesselation control"; 21.674 + case GL_TESS_EVALUATION_SHADER: 21.675 + return "tesselation evaluation"; 21.676 +#endif 21.677 + default: 21.678 + break; 21.679 + } 21.680 + return "<unknown>"; 21.681 +} 21.682 +*/
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/src/shader.h Sun Feb 15 05:14:20 2015 +0200 22.3 @@ -0,0 +1,140 @@ 22.4 +#ifndef SHADER_H_ 22.5 +#define SHADER_H_ 22.6 + 22.7 +#include <vector> 22.8 +#include <string> 22.9 +#include "vmath/vmath.h" 22.10 +#include "opengl.h" 22.11 + 22.12 +class ShaderProg; 22.13 + 22.14 +void bind_shader(const ShaderProg *sdr); 22.15 +const ShaderProg *get_current_shader(); 22.16 + 22.17 + 22.18 +class Shader { 22.19 +private: 22.20 + unsigned int sdr; 22.21 + unsigned int type; 22.22 + std::string name, src; 22.23 + 22.24 +public: 22.25 + Shader(); 22.26 + ~Shader(); 22.27 + 22.28 + unsigned int get_id() const; 22.29 + 22.30 + void set_name(const char *name); 22.31 + const char *get_name() const; 22.32 + 22.33 + bool create(const char *src, unsigned int type); 22.34 + void destroy(); 22.35 + 22.36 + bool load(const char *fname, unsigned int type); 22.37 + 22.38 + 22.39 + // these functions are only meant to be used by the ShaderSet 22.40 + static Shader *create_shader(); 22.41 + static bool load_shader(Shader *sdr, const char *fname); 22.42 + static bool done_shader(Shader *sdr, unsigned int type); 22.43 + static void destroy_shader(Shader *sdr); 22.44 +}; 22.45 + 22.46 +#define VSDR(s) s, GL_VERTEX_SHADER 22.47 +#define FSDR(s) s, GL_FRAGMENT_SHADER 22.48 +#define PSDR(s) FSDR(s) 22.49 +#define GSDR(s) s, GL_GEOMETRY_SHADER 22.50 +#define TCSDR(s) s, GL_TESS_CONTROL_SHADER 22.51 +#define TESDR(s) s, GL_TESS_EVALUATION_SHADER 22.52 + 22.53 +class ShaderProg { 22.54 +private: 22.55 + unsigned int prog; 22.56 + mutable bool must_link; 22.57 + std::vector<Shader*> shaders; 22.58 + 22.59 + struct StateLocCache { int sidx, loc; }; 22.60 + /** a cache of all st_ prefixed uniform locations and their corresponding 22.61 + * index in the global uniform state vector (see unistate.h) 22.62 + */ 22.63 + mutable std::vector<StateLocCache> stloc_cache; 22.64 + 22.65 + void cache_state_uniforms() const; 22.66 + void setup_state_uniforms() const; 22.67 + 22.68 +public: 22.69 + static ShaderProg *current; 22.70 + 22.71 + ShaderProg(); 22.72 + ~ShaderProg(); 22.73 + 22.74 + /// returns the OpenGL object id for this shader program 22.75 + unsigned int get_id() const; 22.76 + 22.77 + /** takes a series of shaders, and constructs a program object by linking 22.78 + * them together. Terminate with a null pointer (don't use 0!) */ 22.79 + bool create(Shader *sdr, ...); 22.80 + /// same as above, but with a va_list instead of variable arguments. 22.81 + bool create(Shader *sdr, va_list ap); 22.82 + /** takes two shaders (vertex and pixel) and constructs a program object by 22.83 + * linking them together. Either one can be null. */ 22.84 + bool create(Shader *vsdr, Shader *psdr); 22.85 + 22.86 + /** takes a series of shader source/shader type pairs and constructs a program 22.87 + * object by linking them together. Terminate with a null pointer (don't use 0!) 22.88 + * You can use the VSDR, PSDR, GSDR, TCSDR, TESDR convenience macros for passing 22.89 + * the pairs. 22.90 + * Example: create(VSDR(vsrc0), VSDR(vsrc1), PSDR(psrc), NULL); 22.91 + */ 22.92 + bool create(const char *src, unsigned int type, ...); 22.93 + /// same as above, but with a va_list instead of variable arguments. 22.94 + bool create(const char *src, unsigned int type, va_list ap); 22.95 + /** takes two shaders source strings (vertex and pixel) and constructs 22.96 + * a program object by linking them together. Either one can be null. */ 22.97 + bool create(const char *vsrc, const char *psrc); 22.98 + 22.99 + void destroy(); 22.100 + 22.101 + /** takes a series of shader filename/shader type pairs, loads the shaders and 22.102 + * constructs a program object by linking them together. Terminate with a null 22.103 + * pointer (don't use 0!). You can use the VSDR, PSDR, GSDR, TCSDR, TESDR convenience 22.104 + * macros for passing the pairs. 22.105 + * Example: load(VSDR("vsdr1.glsl"), VSDR("vsdr2.glsl"), PSDR("pixel.glsl"), NULL); 22.106 + */ 22.107 + bool load(const char *fname, unsigned int type, ...); 22.108 + /// same as above, but with a va_list instead of variable arguments. 22.109 + bool load(const char *fname, unsigned int type, va_list ap); 22.110 + /** takes the filenames of two shader files (vertex and pixel), loads them and 22.111 + * constructs a program object by linking them together. Either one can be null */ 22.112 + bool load(const char *vsrc, const char *psrc); 22.113 + 22.114 + void add_shader(Shader *sdr); 22.115 + bool link() const; 22.116 + 22.117 + void bind() const; 22.118 + 22.119 + int get_attrib_location(const char *name) const; 22.120 + void set_attrib_location(const char *name, int loc) const; 22.121 + 22.122 + int get_uniform_location(const char *name) const; 22.123 + 22.124 + bool set_uniform(int loc, int val) const; 22.125 + bool set_uniform(int loc, float val) const; 22.126 + bool set_uniform(int loc, const Vector2 &v) const; 22.127 + bool set_uniform(int loc, const Vector3 &v) const; 22.128 + bool set_uniform(int loc, const Vector4 &v) const; 22.129 + bool set_uniform(int loc, const Matrix3x3 &m) const; 22.130 + bool set_uniform(int loc, const Matrix4x4 &m) const; 22.131 + 22.132 + bool set_uniform(const char *name, int val) const; 22.133 + bool set_uniform(const char *name, float val) const; 22.134 + bool set_uniform(const char *name, const Vector2 &v) const; 22.135 + bool set_uniform(const char *name, const Vector3 &v) const; 22.136 + bool set_uniform(const char *name, const Vector4 &v) const; 22.137 + bool set_uniform(const char *name, const Matrix3x3 &m) const; 22.138 + bool set_uniform(const char *name, const Matrix4x4 &m) const; 22.139 + 22.140 + friend void setup_unistate(const ShaderProg*); 22.141 +}; 22.142 + 22.143 +#endif // SHADER_H_
23.1 --- a/src/sim.cc Sat Feb 14 10:08:00 2015 +0200 23.2 +++ b/src/sim.cc Sun Feb 15 05:14:20 2015 +0200 23.3 @@ -64,3 +64,39 @@ 23.4 { 23.5 return gravity; 23.6 } 23.7 + 23.8 +bool SimWorld::collide(const GObject *obj, HitPoint *hit) const 23.9 +{ 23.10 + CoCollider *co = COCAST(CoCollider, obj->get_component("collider")); 23.11 + if(co) { 23.12 + return collide(co, hit); 23.13 + } 23.14 + return false; // no collisions if it doesn't have a collider component 23.15 +} 23.16 + 23.17 +bool SimWorld::collide(const CoCollider *col, HitPoint *hit) const 23.18 +{ 23.19 + if(!col->shape) { 23.20 + return false; 23.21 + } 23.22 + 23.23 + // TODO do something better 23.24 + std::list<CoRigid*>::const_iterator it = rigid.begin(); 23.25 + while(it != rigid.end()) { 23.26 + const CoRigid *r = *it++; 23.27 + const GObject *obj2 = r->get_object(); 23.28 + if(!obj2 || obj2 == col->get_object()) { 23.29 + continue; 23.30 + } 23.31 + 23.32 + const CoCollider *col2 = COCAST(CoCollider, obj2->get_component("collider")); 23.33 + if(!col2 || !col2->shape) { 23.34 + continue; 23.35 + } 23.36 + 23.37 + if(col->shape->collide(col2->shape, hit)) { 23.38 + return true; 23.39 + } 23.40 + } 23.41 + return false; 23.42 +}
24.1 --- a/src/sim.h Sat Feb 14 10:08:00 2015 +0200 24.2 +++ b/src/sim.h Sun Feb 15 05:14:20 2015 +0200 24.3 @@ -3,6 +3,7 @@ 24.4 24.5 #include <list> 24.6 #include "co_phys.h" 24.7 +#include "co_collider.h" 24.8 #include "gobj.h" 24.9 24.10 class SimWorld { 24.11 @@ -25,6 +26,9 @@ 24.12 24.13 void set_gravity(const Vector3 &v); 24.14 const Vector3 &get_gravity() const; 24.15 + 24.16 + bool collide(const GObject *obj, HitPoint *hit = 0) const; 24.17 + bool collide(const CoCollider *col, HitPoint *hit = 0) const; 24.18 }; 24.19 24.20 #endif // COENG_SIM_H_
25.1 --- a/src/test.cc Sat Feb 14 10:08:00 2015 +0200 25.2 +++ b/src/test.cc Sun Feb 15 05:14:20 2015 +0200 25.3 @@ -3,15 +3,20 @@ 25.4 #include <assert.h> 25.5 #include <vector> 25.6 25.7 +#include "opengl.h" 25.8 #ifndef __APPLE__ 25.9 #include <GL/glut.h> 25.10 #else 25.11 #include <GLUT/glut.h> 25.12 #endif 25.13 25.14 +#include "objfile.h" 25.15 +#include "mesh.h" 25.16 #include "gobj.h" 25.17 #include "co_xform.h" 25.18 #include "co_dbgvis.h" 25.19 +#include "co_mesh.h" 25.20 +#include "co_phys.h" 25.21 #include "sim.h" 25.22 25.23 static bool init(); 25.24 @@ -22,8 +27,9 @@ 25.25 static void keyb(unsigned char key, int x, int y); 25.26 static void mouse(int bn, int st, int x, int y); 25.27 static void motion(int x, int y); 25.28 +static Mesh *load_mesh(const char *fname); 25.29 25.30 -float cam_theta, cam_phi = 25, cam_dist = 8; 25.31 +float cam_theta, cam_phi = 25, cam_dist = 10; 25.32 25.33 std::vector<GObject*> objects; 25.34 SimWorld simworld; 25.35 @@ -54,6 +60,8 @@ 25.36 25.37 static bool init() 25.38 { 25.39 + init_opengl(); 25.40 + 25.41 glEnable(GL_DEPTH_TEST); 25.42 glEnable(GL_CULL_FACE); 25.43 25.44 @@ -62,27 +70,51 @@ 25.45 float ldir[] = {-1, 1, 2, 0}; 25.46 glLightfv(GL_LIGHT0, GL_POSITION, ldir); 25.47 25.48 - GObject *obj = new GObject; 25.49 - obj->add_component(new CoSphereVis); 25.50 + GObject *obj; 25.51 + 25.52 + Mesh *mesh = load_mesh("lucy.obj"); 25.53 + if(!mesh) { 25.54 + return false; 25.55 + } 25.56 + 25.57 + obj = new GObject; 25.58 obj->add_component(new CoXForm); 25.59 obj->add_component(new CoPRS); 25.60 - obj->add_component(new CoRigid); 25.61 - COCAST(CoPRS, obj->get_component("prs"))->pos = Vector3(5, 2, 0); 25.62 + obj->add_component(new CoMesh); 25.63 + gobj_co_prs(obj)->pos = Vector3(-3, 0, 0); 25.64 + gobj_co_mesh(obj)->mesh = mesh; 25.65 objects.push_back(obj); 25.66 - simworld.add_object(obj); 25.67 25.68 obj = new GObject; 25.69 obj->add_component(new CoSphereVis); 25.70 obj->add_component(new CoXForm); 25.71 obj->add_component(new CoPRS); 25.72 - COCAST(CoPRS, obj->get_component("prs"))->pos = Vector3(-5, 1, 0); 25.73 + gobj_co_prs(obj)->pos = Vector3(3, 3, 0); 25.74 + obj->add_component(new CoRigid); 25.75 + obj->add_component(new CoCollider); 25.76 + gobj_co_collider(obj)->shape = new Sphere; 25.77 objects.push_back(obj); 25.78 + simworld.add_object(obj); 25.79 + 25.80 + obj = new GObject; 25.81 + obj->add_component(new CoXForm); 25.82 + obj->add_component(new CoPRS); 25.83 + obj->add_component(new CoRigid); 25.84 + obj->add_component(new CoCollider); 25.85 + gobj_co_collider(obj)->shape = new Plane; 25.86 + gobj_co_rigid(obj)->set_fixed(true); 25.87 + objects.push_back(obj); 25.88 + simworld.add_object(obj); 25.89 25.90 return true; 25.91 } 25.92 25.93 static void cleanup() 25.94 { 25.95 + for(size_t i=0; i<objects.size(); i++) { 25.96 + delete objects[i]; 25.97 + } 25.98 + objects.clear(); 25.99 } 25.100 25.101 static void update() 25.102 @@ -108,6 +140,7 @@ 25.103 glTranslatef(0, 0, -cam_dist); 25.104 glRotatef(cam_phi, 1, 0, 0); 25.105 glRotatef(cam_theta, 0, 1, 0); 25.106 + glTranslatef(0, -0.5, 0); 25.107 25.108 float floor_col[] = {0.2, 0.8, 0.2, 1}; 25.109 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, floor_col); 25.110 @@ -120,11 +153,11 @@ 25.111 glVertex3f(-10, 0, -10); 25.112 glEnd(); 25.113 25.114 + float obj_col[] = {0.9, 0.9, 0.9, 1}; 25.115 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, obj_col); 25.116 + 25.117 for(size_t i=0; i<objects.size(); i++) { 25.118 - CoSphereVis *co = COCAST(CoSphereVis, objects[i]->get_component("spherevis")); 25.119 - if(co) { 25.120 - co->draw(); 25.121 - } 25.122 + objects[i]->draw(); 25.123 } 25.124 25.125 glutSwapBuffers(); 25.126 @@ -185,3 +218,19 @@ 25.127 if(cam_dist < 0.0) cam_dist = 0.0; 25.128 } 25.129 } 25.130 + 25.131 +static Mesh *load_mesh(const char *fname) 25.132 +{ 25.133 + struct objfile *objf = objf_load(fname); 25.134 + if(!objf) { 25.135 + return 0; 25.136 + } 25.137 + int nverts = objf_vertex_count(objf); 25.138 + 25.139 + Mesh *m = new Mesh; 25.140 + m->set_attrib_data(MESH_ATTR_VERTEX, 3, nverts, objf_vertices(objf)); 25.141 + m->set_attrib_data(MESH_ATTR_NORMAL, 3, nverts, objf_normals(objf)); 25.142 + m->set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts, objf_texcoords(objf)); 25.143 + objf_free(objf); 25.144 + return m; 25.145 +}