Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 288)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 294)
@@ -28,5 +28,14 @@
 	m_index_count  = m_mesh_data->get_index_channel()->count;
 	m_vertex_count = m_mesh_data->get_channel<vertex_t>()->count;
-	m_frame_count  = m_mesh_data->get_channel<vertex_pn>()->count / m_vertex_count;
+	m_vchannel     = m_mesh_data->get_channel<vertex_pnt>();
+	m_vsize        = sizeof( vertex_pnt );
+	m_has_tangent  = true;
+	if ( m_vchannel == nullptr )
+	{
+		m_vchannel     = m_mesh_data->get_channel<vertex_pn>();
+		m_has_tangent  = false;
+		m_vsize        = sizeof( vertex_pn );
+	}
+	m_frame_count  = m_vchannel->count / m_vertex_count;
 }
 
@@ -116,6 +125,7 @@
 nv::keyframed_mesh_gpu::keyframed_mesh_gpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map, program* a_program )
 	: keyframed_mesh( a_device, a_data, a_tag_map )
-	, m_loc_next_position( 0 )
-	, m_loc_next_normal( 0 )
+	, m_loc_next_position( -1 )
+	, m_loc_next_normal( -1 )
+	, m_loc_next_tangent( -1 )
 	, m_gpu_last_frame( 0xFFFFFFFF )
 	, m_gpu_next_frame( 0xFFFFFFFF )
@@ -123,8 +133,11 @@
 	m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
 	m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
+	m_loc_next_tangent  = a_program->try_get_attribute_location( "nv_next_tangent" );
 	m_va = a_device->create_vertex_array( a_data, STATIC_DRAW );
 	vertex_buffer* vb = m_va->find_buffer( slot::POSITION );
-	m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0,              sizeof( vertex_pn ), false );
-	m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), sizeof( vertex_pn ), false );
+	m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0, m_vsize, false );
+	m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
+	if ( m_has_tangent )
+		m_va->add_vertex_buffer( m_loc_next_tangent, vb, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
 }
 
@@ -136,12 +149,17 @@
 	if ( m_gpu_last_frame != m_last_frame )
 	{
-		m_va->update_vertex_buffer( slot::POSITION, m_last_frame * m_vertex_count * sizeof( vertex_pn ) );
-		m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * m_vertex_count * sizeof( vertex_pn ) + sizeof( vec3 ) );
+		m_va->update_vertex_buffer( slot::POSITION, m_last_frame * m_vertex_count * m_vsize );
+		m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
+		if ( m_has_tangent && m_loc_next_tangent != -1 )
+		{
+			m_va->update_vertex_buffer( slot::TANGENT,   m_last_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
+		}
 		m_gpu_last_frame = m_last_frame;
 	}
 	if ( m_gpu_next_frame != m_next_frame )
 	{
-		m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * sizeof( vertex_pn ) );
-		m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * m_vertex_count * sizeof( vertex_pn ) + sizeof( vec3 ) );
+		m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * m_vsize );
+		m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
+		m_va->update_vertex_buffer( m_loc_next_tangent,   m_next_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
 		m_gpu_next_frame = m_next_frame;
 	}
@@ -151,6 +169,6 @@
 	: keyframed_mesh( a_device, a_data, a_tag_map )
 {
-	m_vb = a_device->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( vertex_pn ), (void*)m_mesh_data->get_channel<vertex_pn>()->data );
-	m_va->add_vertex_buffers( m_vb, m_mesh_data->get_channel<vertex_pn>() );
+	m_vb = a_device->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * m_vsize, (void*)m_vchannel->data );
+	m_va->add_vertex_buffers( m_vb, m_vchannel );
 
 	nv::vertex_buffer* vb = a_device->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( nv::vec2 ), (void*)m_mesh_data->get_channel<vertex_t>()->data );
@@ -160,5 +178,5 @@
 	m_va->set_index_buffer( ib, m_mesh_data->get_index_channel()->desc.slots[0].etype, true );
 
-	m_vertex.resize( m_vertex_count );
+	m_data = new uint8[ m_vertex_count * m_vsize ];
 }
 
@@ -167,16 +185,39 @@
 	animated_mesh::update( ms );
 
-	const vertex_pn* data = m_mesh_data->get_channel_data<vertex_pn>();
-	const vertex_pn* prev = data + m_vertex_count * m_last_frame;
-	const vertex_pn* next = data + m_vertex_count * m_next_frame;
-
-	for ( size_t i = 0; i < m_vertex_count; ++i )
-	{
-		m_vertex[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
-		m_vertex[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
+	// TODO: this could be done generic for any data
+	if ( m_has_tangent )
+	{
+		const vertex_pnt* data = m_mesh_data->get_channel_data<vertex_pnt>();
+		const vertex_pnt* prev = data + m_vertex_count * m_last_frame;
+		const vertex_pnt* next = data + m_vertex_count * m_next_frame;
+		      vertex_pnt* vtx  = (vertex_pnt*)m_data;
+		for ( size_t i = 0; i < m_vertex_count; ++i )
+		{
+			vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
+			vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
+			vtx[i].tangent  = glm::mix( prev[i].tangent,  next[i].tangent,   m_interpolation );
+		}
+	}
+	else
+	{
+		const vertex_pn* data = m_mesh_data->get_channel_data<vertex_pn>();
+		const vertex_pn* prev = data + m_vertex_count * m_last_frame;
+		const vertex_pn* next = data + m_vertex_count * m_next_frame;
+		      vertex_pn* vtx  = (vertex_pn*)m_data;
+
+		for ( size_t i = 0; i < m_vertex_count; ++i )
+		{
+			vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
+			vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
+		}
 	}
 
 	m_vb->bind();
-	m_vb->update( m_vertex.data(), 0, m_vertex_count * sizeof( vertex_pn ) );
+	m_vb->update( m_data, 0, m_vertex_count * m_vsize );
 	m_vb->unbind();
 }
+
+nv::keyframed_mesh_cpu::~keyframed_mesh_cpu()
+{
+	delete[] m_data;
+}
