Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 471)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 475)
@@ -11,37 +11,5 @@
 #include "nv/stl/unordered_map.hh"
 
-void nv::skeletal_animation_entry::initialize()
-{
-	m_root      = uint32(-1);
-	m_prepared  = false;
-	m_children  = nullptr;
-	m_offsets   = nullptr;
-	m_bone_ids  = new sint16[m_node_data->size()];
-
-	NV_ASSERT( m_node_data, "node data empty!" );
-
-	if ( !m_node_data->is_flat() )
-	{
-		m_children = new vector< uint32 >[m_node_data->size()];
-		for ( uint32 n = 0; n < m_node_data->size(); ++n )
-		{
-			const data_channel_set* node = (*m_node_data)[n];
-			if ( node->get_parent_id() != -1 )
-			{
-				m_children[ node->get_parent_id()].push_back( n );
-			}
-			else
-			{
-				if ( m_root >= 0 )
-				{
-					m_root = uint32( -2 );
-				}
-				else
-					m_root = n;
-			}
-		}
-		NV_ASSERT( m_root != uint32( -1 ), "Animation without root!" );
-	}
-}
+#include "nv/core/logging.hh"
 
 void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 a_ms_time ) const
@@ -70,97 +38,10 @@
 	}
 
-	if ( !m_node_data->is_flat() )
-	{
-		if ( m_root == uint32( -2 ) ) // multi-root
-		{
-			for ( uint32 n = 0; n < m_node_data->size(); ++n )
-				if ( ( *m_node_data )[n]->get_parent_id() == -1 )
-					animate_rec( data, fframe, n, mat4() );
-		}
-		else
-			animate_rec( data, fframe, m_root, mat4() );
-		return;
-	}
-
-	for ( uint32 n = 0; n < m_node_data->size(); ++n )
-		if ( m_bone_ids[n] >= 0 )
-		{
-			const data_channel_set* node = (*m_node_data)[n];
-			nv::mat4 node_mat( node->get_transform() );
-
-			if ( node->size() > 0 )
-			{
-				raw_channel_interpolator interpolator( node, m_interpolation_key );
-				node_mat = interpolator.get< mat4 >( fframe );
-			}
-
-			sint16 bone_id = m_bone_ids[n];
-			data[ bone_id ] = node_mat * m_offsets[ bone_id ];
-		}
+	m_data.animate( data, fframe );
 }
 
 void nv::skeletal_animation_entry::prepare( const mesh_nodes_data* bones )
 {
-	if ( m_prepared ) return;
-	nv::hash_store< shash64, uint16 > bone_names;
-	m_offsets = new mat4[ bones->size() ];
-	for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
-	{
-		const data_channel_set* bone = (*bones)[ bi ];
-		bone_names[ bone->get_name() ] = bi;
-		m_offsets[bi] = bone->get_transform();
-	}
-
-	for ( uint32 n = 0; n < m_node_data->size(); ++n )
-	{
-		const data_channel_set* node = (*m_node_data)[ n ];
-		sint16 bone_id = -1;
-
-		auto bi = bone_names.find( node->get_name() );
-		if ( bi != bone_names.end() )
-		{
-			bone_id = sint16( bi->second );
-		}
-		m_bone_ids[n] = bone_id;
-
-		if ( m_interpolation_key.size() == 0 && node->size() > 0 )
-			m_interpolation_key = node->get_interpolation_key();
-
-	}
-	m_prepared = true;
-}
-
-void nv::skeletal_animation_entry::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
-{
-	// TODO: fix transforms, which are now embedded,
-	//       see note in assimp_loader.cc:load_node
-	const data_channel_set* node = ( *m_node_data )[ node_id ];
-	mat4 node_mat( node->get_transform() );
-
-	if ( node->size() > 0 )
-	{
-		raw_channel_interpolator interpolator( node, m_interpolation_key );
-		node_mat = interpolator.get< mat4 >( time );
-	}
-
-	mat4 global_mat = parent_mat * node_mat;
-
-	sint16 bone_id = m_bone_ids[ node_id ];
-	if ( bone_id >= 0 )
-	{
-		data[ bone_id ] = global_mat * m_offsets[ bone_id ];
-	}
-
-	for ( auto child : m_children[ node_id ] )
-	{
-		animate_rec( data, time, child, global_mat );
-	}
-}
-
-nv::skeletal_animation_entry::~skeletal_animation_entry()
-{
-	delete[] m_offsets;
-	delete[] m_children;
-	delete[] m_bone_ids;
+	m_data.prepare( bones );
 }
 
@@ -198,6 +79,4 @@
 nv::transform nv::skeletal_mesh::get_node_transform( uint32 node_id ) const
 {
-	if ( node_id == 0 ) return transform();
-	if ( node_id == uint32(-1) ) return transform( m_transform[0] );
 	return transform( m_transform[ node_id ] );
 }
