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 ? &reg_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 ? &reg_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 ? &reg_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 ? &reg_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 ? &reg_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 +}