Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 418)
+++ trunk/src/formats/assimp_loader.cc	(revision 419)
@@ -418,6 +418,6 @@
 	}
 
-	data->data = key_channel_set_creator::create( 2 );
-	key_channel_set_creator key_set( data->data );
+	data->data = data_channel_set_creator::create( 2 );
+	data_channel_set_creator key_set( data->data );
 
 	assimp_key_p* pchannel = key_set.add_channel< assimp_key_p >( node->mNumPositionKeys ).data();
Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 418)
+++ trunk/src/formats/md3_loader.cc	(revision 419)
@@ -429,6 +429,6 @@
 		nodes[i].parent_id = -1;
 		nodes[i].target_id = -1;
-		nodes[i].data      = key_channel_set_creator::create( 1 );
-		load_tags( key_channel_set_creator( nodes[i].data ).add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
+		nodes[i].data      = data_channel_set_creator::create( 1 );
+		load_tags( data_channel_set_creator( nodes[i].data ).add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
 	}
 	return new mesh_nodes_data( "tags", node_count, nodes );
Index: trunk/src/formats/md5_loader.cc
===================================================================
--- trunk/src/formats/md5_loader.cc	(revision 418)
+++ trunk/src/formats/md5_loader.cc	(revision 419)
@@ -250,6 +250,6 @@
 				nodes[i].transform = mat4();
 				nodes[i].target_id = -1;
-				nodes[i].data = key_channel_set_creator::create( 1 );
-				key_channel_set_creator( nodes[i].data ).add_channel< md5_key_t >( num_frames );
+				nodes[i].data = data_channel_set_creator::create( 1 );
+				data_channel_set_creator( nodes[i].data ).add_channel< md5_key_t >( num_frames );
 				next_line( sstream );
 			}
Index: trunk/src/formats/nmd_loader.cc
===================================================================
--- trunk/src/formats/nmd_loader.cc	(revision 418)
+++ trunk/src/formats/nmd_loader.cc	(revision 419)
@@ -121,6 +121,6 @@
 		if ( ch_count > 0 )
 		{
-			key_channel_set* kdata = key_channel_set_creator::create( ch_count );
-			key_channel_set_creator kaccess( kdata );
+			data_channel_set* kdata = data_channel_set_creator::create( ch_count );
+			data_channel_set_creator kaccess( kdata );
 			m_node_array[i].data = kdata;
 			for ( uint32 c = 0; c < ch_count; ++c )
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 418)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 419)
@@ -39,4 +39,9 @@
 	m_frame_count  = pos_size / m_vertex_count;
 	m_pbuffer      = buffer();
+
+	if ( m_tag_map && m_tag_map->get_count() > 0 )
+	{
+		m_interpolation_key = m_tag_map->get_node( 0 )->data->get_interpolation_key();
+	}
 }
 
@@ -50,9 +55,8 @@
 	if ( !m_tag_map ) return transform();
 	NV_ASSERT( node_id < m_tag_map->get_count(), "TAGMAP FAIL" );
-	const key_channel_set* data = m_tag_map->get_node( node_id )->data;
+	const data_channel_set* data = m_tag_map->get_node( node_id )->data;
 	NV_ASSERT( data, "TAG FAIL" );
-	transform last = data->get_raw_transform( m_last_frame );
-	transform next = data->get_raw_transform( m_next_frame );
-	return interpolate( last, next, m_interpolation  );
+	raw_channel_interpolator interpolator( data, m_interpolation_key );
+	return interpolator.get< transform >( m_last_frame, m_next_frame, m_interpolation );
 }
 
Index: trunk/src/gfx/mesh_creator.cc
===================================================================
--- trunk/src/gfx/mesh_creator.cc	(revision 418)
+++ trunk/src/gfx/mesh_creator.cc	(revision 419)
@@ -19,6 +19,6 @@
 	{
 		sint16 parent_id = m_data->m_nodes[i].parent_id;
-		key_channel_set* keys   = m_data->m_nodes[i].data;
-		key_channel_set* pkeys  = ( parent_id != -1 ? m_data->m_nodes[parent_id].data : nullptr );
+		data_channel_set* keys   = m_data->m_nodes[i].data;
+		data_channel_set* pkeys  = ( parent_id != -1 ? m_data->m_nodes[parent_id].data : nullptr );
 		size_t count     = ( keys ? keys->get_channel_size(0) : 0 );
 		size_t pcount    = ( pkeys ? pkeys->get_channel_size(0) : 0 );
@@ -46,8 +46,4 @@
 }
 
-// TODO: DELETE
-struct assimp_key_p  { float time; nv::vec3 position; };
-struct assimp_key_r  { float time; nv::quat rotation; };
-
 
 void nv::mesh_nodes_creator::merge_keys()
@@ -55,5 +51,5 @@
 	for ( size_t i = 0; i < m_data->get_count(); ++i )
 	{
-		key_channel_set* old_keys = m_data->m_nodes[i].data;
+		data_channel_set* old_keys = m_data->m_nodes[i].data;
 		if ( old_keys && old_keys->size() > 0 )
 		{
@@ -69,9 +65,10 @@
 			}
 
-			key_channel_set* new_keys = key_channel_set_creator::create( 1 );
-			key_channel_set_creator nk_access( new_keys );
+			data_channel_set* new_keys = data_channel_set_creator::create( 1 );
+			data_channel_set_creator nk_access( new_keys );
 			data_channel_access< nv_key_transform > kt_channel( nk_access.add_channel<nv_key_transform>( max_keys ) );
 
-			data_descriptor final_key = old_keys->get_final_key();
+			raw_channel_interpolator interpolator( old_keys );
+			data_descriptor final_key = interpolator.get_interpolation_key();
 
 			for ( unsigned n = 0; n < max_keys; ++n )
@@ -83,7 +80,7 @@
 				{
 					size_t idx = nv::min( old_keys->get_channel_size(c) - 1, n );
-					pkey += old_keys->get_raw( *old_keys->get_channel(c), idx, pkey );
-				}
-				kt_channel.data()[n].tform = extract_transform_raw( final_key, key );
+					pkey += raw_channel_interpolator::get_raw( *old_keys->get_channel(c), idx, pkey );
+				}
+				kt_channel.data()[n].tform = extract_key_raw< nv::transform >( final_key, key );
 			}
 
@@ -106,5 +103,5 @@
 		if ( node.data )
 		{
-			key_channel_set* kdata  = node.data;
+			data_channel_set* kdata  = node.data;
 			for ( size_t c = 0; c < kdata->size(); ++c )
 			{
@@ -332,5 +329,5 @@
 		}
 	}
-	delete tangents2;
+	delete[] tangents2;
 
 	data_channel_set_creator( m_data ).set_channel( n_channel_index, merge_channels( *n_channel, g_channel ) );
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 418)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 419)
@@ -91,4 +91,16 @@
 
 
+void nv::skeletal_animation_entry_cpu::initialize()
+{
+	for ( size_t i = 0; i < m_node_data->get_count(); ++i )
+	{
+		if ( m_node_data->get_node( i )->data )
+		{
+			m_interpolation_key = m_node_data->get_node( i )->data->get_interpolation_key();
+			break;
+		}
+	}
+}
+
 void nv::skeletal_animation_entry_cpu::update_skeleton( transform* skeleton, float time ) const
 {
@@ -100,5 +112,6 @@
 	for ( size_t i = 0; i < m_node_data->get_count(); ++i )
 	{
-		skeleton[i] = m_node_data->get_node(i)->data->get_transform( frame_num );
+		raw_channel_interpolator interpolator( m_node_data->get_node( i )->data, m_interpolation_key );
+		skeleton[i] = interpolator.get< transform >( frame_num );
 	}
 }
@@ -112,4 +125,6 @@
 	m_bone_ids  = new sint16[ node_count ];
 
+	NV_ASSERT( m_node_data, "node data empty!" );
+
 	if ( !m_node_data->is_flat() )
 	{
@@ -146,5 +161,6 @@
 			if ( node->data )
 			{
-				node_mat = node->data->get_matrix( anim_time );
+				raw_channel_interpolator interpolator( node->data, m_interpolation_key );
+				node_mat = interpolator.get< mat4 >( anim_time );
 			}
 
@@ -177,4 +193,8 @@
 		}
 		m_bone_ids[n] = bone_id;
+
+		if ( m_interpolation_key.size() == 0 && node->data )
+			m_interpolation_key = node->data->get_interpolation_key();
+
 	}
 	m_prepared = true;
@@ -190,5 +210,6 @@
 	if ( node->data )
 	{
-		node_mat = node->data->get_matrix( time );
+		raw_channel_interpolator interpolator( node->data, m_interpolation_key );
+		node_mat = interpolator.get< mat4 >( time );
 	}
 
