Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 138)
+++ trunk/src/formats/obj_loader.cc	(revision 147)
@@ -119,10 +119,12 @@
 struct mesh_obj_reader : public obj_reader
 {
-	mesh_obj_reader( mesh* m ) : m_mesh( m ), m_position( nullptr ), m_normal( nullptr ), m_tex_coord( nullptr ) {}
+	mesh_obj_reader( mesh* m ) : m_mesh( m ), m_position( nullptr ), m_normal( nullptr ), m_tex_coord( nullptr ), m_tangent( nullptr ) {}
 	virtual std::size_t add_face( uint32* v, uint32* t, uint32* n, size_t count );
+	virtual void calculate_tangents();
 
 	vertex_attribute< vec3 >* m_position;
 	vertex_attribute< vec3 >* m_normal;
 	vertex_attribute< vec2 >* m_tex_coord;
+	vertex_attribute< vec4 >* m_tangent;
 	mesh* m_mesh;
 };
@@ -169,6 +171,82 @@
 }
 
-nv::obj_loader::obj_loader()
-	: m_mesh( nullptr )
+// based on http://www.terathon.com/code/tangent.html
+void mesh_obj_reader::calculate_tangents()
+{
+	m_tangent = m_mesh->add_attribute< vec4 >( "tangent" );
+
+	std::vector< vec3 >& vp = m_position->get();
+	std::vector< vec2 >& vt = m_tex_coord->get();
+	std::vector< vec3 >& vn = m_normal->get();
+	std::vector< vec4 >& tg = m_tangent->get();
+
+	std::size_t count  = vp.size();
+	std::size_t tcount = count / 3;
+
+	std::vector< vec3 > tan1( count );
+	std::vector< vec3 > tan2( count );
+	tg.resize( count );
+
+	for (std::size_t a = 0; a < tcount; ++a )
+	{
+		uint32 i1 = a * 3;
+		uint32 i2 = a * 3 + 1;
+		uint32 i3 = a * 3 + 2;
+
+		const vec3& v1 = vp[i1];
+		const vec3& v2 = vp[i2];
+		const vec3& v3 = vp[i3];
+
+		const vec2& w1 = vt[i1];
+		const vec2& w2 = vt[i2];
+		const vec2& w3 = vt[i3];
+
+		vec3 xyz1 = v2 - v1;
+		vec3 xyz2 = v3 - v1;
+		vec2 st1  = w2 - w1;
+		vec2 st2  = w3 - w1;
+
+		float x1 = v2.x - v1.x;
+		float y1 = v2.y - v1.y;
+		float z1 = v2.z - v1.z;
+
+		float x2 = v3.x - v1.x;
+		float y2 = v3.y - v1.y;
+		float z2 = v3.z - v1.z;
+
+		float s1 = w2.x - w1.x;
+		float t1 = w2.y - w1.y;
+		float s2 = w3.x - w1.x;
+		float t2 = w3.y - w1.y;
+
+		float r = 1.0f / (s1 * t2 - s2 * t1);
+
+		vec3 sdir = ( t2 * xyz1 - t1 * xyz2 ) * r;
+		vec3 tdir = ( s1 * xyz2 - s2 * xyz1 ) * r;
+
+		// the += below obviously doesn't make sense in this case, but I'll
+		// leave it here for when I move to indices
+		tan1[i1] += sdir;
+		tan1[i2] += sdir;
+		tan1[i3] += sdir;
+
+		tan2[i1] += tdir;
+		tan2[i2] += tdir;
+		tan2[i3] += tdir;
+	}
+
+	for (std::size_t a = 0; a < count; ++a )
+	{
+		const vec3& n = vn[a];
+		const vec3& t = tan1[a];
+
+		tg[a] = vec4( glm::normalize(t - n * glm::dot( n, t )), 
+		    (glm::dot(glm::cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f );
+	}
+
+}
+
+nv::obj_loader::obj_loader( bool tangents )
+	: m_mesh( nullptr ), m_tangents( tangents )
 {
 
@@ -191,4 +269,8 @@
 	reader.read_stream( sstream );
 	m_size = reader.size;
+	if ( m_tangents )
+	{
+		reader.calculate_tangents();
+	}
 	return true;
 }
