Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 475)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 477)
@@ -13,5 +13,5 @@
 #include "nv/core/logging.hh"
 
-void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 a_ms_time ) const
+void nv::skeletal_animation_entry::update_skeleton( skeleton_instance& data, uint32 a_ms_time ) const
 {
 	float  fframe   = ( a_ms_time * 0.001f ) * m_fps;
@@ -38,14 +38,16 @@
 	}
 
-	m_data.animate( data, fframe );
+	if ( data.size() == 0 )
+		data.initialize( m_temp_anim->size() );
+	data.animate( m_temp_anim, m_data, fframe );
 }
 
 void nv::skeletal_animation_entry::prepare( const mesh_nodes_data* bones )
 {
-	m_data.prepare( bones );
+	m_data.prepare( m_temp_anim, bones ? bones : m_temp_anim );
 }
 
 nv::skeletal_mesh::skeletal_mesh( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
-	: m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr ), m_parent_id(-1)
+	: m_skeleton( a_bone_data ? a_bone_data->size() : 0 ), m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_parent_id(-1)
 {
 	if ( a_mesh )
@@ -55,33 +57,25 @@
 		m_parent_id = a_mesh->get_parent_id();
 	}
-	if ( m_bone_data )
-	{
-		m_transform = new mat4[ m_bone_data->size() ];
-	}
 }
 
-void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
+void nv::skeletal_mesh::update_animation( animation_entry& a_anim, uint32 a_anim_time )
 {
-	if ( m_bone_data && a_anim )
-	{
-		skeletal_animation_entry * anim = static_cast<skeletal_animation_entry*>( a_anim );
-		anim->prepare( m_bone_data );
-		anim->update_skeleton( m_transform, a_anim_time );
-	}
+	skeletal_animation_entry& anim = static_cast<skeletal_animation_entry&>( a_anim );
+	anim.prepare( m_bone_data );
+	anim.update_skeleton( m_skeleton, a_anim_time );
 }
 
-void nv::skeletal_mesh::update( program a_program )
+void nv::skeletal_mesh::update_program( program a_program )
 {
-	if ( m_bone_data )
-		m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->size() );
+	m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_skeleton.transforms(), m_skeleton.size() );
 }
 
 nv::transform nv::skeletal_mesh::get_node_transform( uint32 node_id ) const
 {
-	return transform( m_transform[ node_id ] );
+	return transform( get_node_matrix( node_id ) );
 }
 
 nv::mat4 nv::skeletal_mesh::get_node_matrix( uint32 node_id ) const
 {
-	return m_transform[ node_id ];
+	return m_skeleton.transforms()[ node_id ];
 }
Index: trunk/src/gfx/skeleton_instance.cc
===================================================================
--- trunk/src/gfx/skeleton_instance.cc	(revision 475)
+++ trunk/src/gfx/skeleton_instance.cc	(revision 477)
@@ -7,78 +7,74 @@
 #include "nv/gfx/skeleton_instance.hh"
 
-void nv::skeleton_instance::prepare( const mesh_nodes_data* bones )
+void nv::skeleton_binding::prepare( const mesh_nodes_data* node_data, const mesh_nodes_data* bone_data )
 {
-	if ( m_offsets || m_indices ) return;
-	hash_store< shash64, uint16 > bone_names;
-	m_offsets = new mat4[bones->size()];
-	m_indices = new sint16[m_data->size()];
+	if ( !m_offsets || !m_indices )
+	{
+		// TODO: either fixed size struct or static allocator
+		hash_store< shash64, uint16 > bone_names;
+		m_offsets = new mat4[bone_data->size()];
+		m_indices = new sint16[node_data->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 ( nv::uint16 bi = 0; bi < bone_data->size(); ++bi )
+		{
+			const data_channel_set* bone = ( *bone_data )[bi];
+			bone_names[bone->get_name()] = bi;
+			m_offsets[bi] = bone->get_transform();
+		}
+
+		for ( uint32 n = 0; n < node_data->size(); ++n )
+		{
+			const data_channel_set* node = ( *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_indices[n] = bone_id;
+
+		}
 	}
 
-	for ( uint32 n = 0; n < m_data->size(); ++n )
+	if ( m_key.size() == 0 )
 	{
-		const data_channel_set* node = ( *m_data )[n];
-		sint16 bone_id = -1;
+		for ( uint32 n = 0; n < node_data->size(); ++n )
+			if ( ( *node_data )[n]->size() > 0 )
+			{
+				m_key = ( *node_data )[n]->get_interpolation_key();
+				break;
+			}
+	}
 
-		auto bi = bone_names.find( node->get_name() );
-		if ( bi != bone_names.end() )
+}
+
+void nv::skeleton_instance::animate( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame )
+{
+	if ( m_transform.size() > 0 )
+	{
+		if ( node_data->is_flat() )
 		{
-			bone_id = sint16( bi->second );
+			animate_flat( node_data, binding, frame );
 		}
-		m_indices[n] = bone_id;
-
-		if ( m_key.size() == 0 && node->size() > 0 )
-			m_key = node->get_interpolation_key();
+		else
+		{
+			for ( uint32 n = 0; n < node_data->size(); ++n )
+				if ( ( *node_data )[n]->get_parent_id() == -1 )
+					animate_rec( node_data, binding, frame, n, mat4() );
+		}
 	}
 }
 
-void nv::skeleton_instance::animate( mat4* data, float frame ) const
-{
-	if ( m_data->is_flat() )
-	{
-		animate_flat( data, frame );
-	}
-	else
-	{
-		for ( uint32 n = 0; n < m_data->size(); ++n )
-			if ( ( *m_data )[n]->get_parent_id() == -1 )
-				animate_rec( data, frame, n, mat4() );
-	}
-}
-
-void nv::skeleton_instance::animate_flat( mat4* data, float frame ) const
-{
-	for ( uint32 n = 0; n < m_data->size(); ++n )
-		if ( m_indices[n] >= 0 )
-		{
-			const data_channel_set* node = ( *m_data )[n];
-			nv::mat4 node_mat( node->get_transform() );
-
-			if ( node->size() > 0 )
-			{
-				raw_channel_interpolator interpolator( node, m_key );
-				node_mat = interpolator.get< mat4 >( frame );
-			}
-
-			sint16 bone_id = m_indices[n];
-			data[bone_id] = node_mat * m_offsets[bone_id];
-		}
-}
-
-void nv::skeleton_instance::animate_rec( mat4* data, float frame, uint32 id, const mat4& parent ) const
+void nv::skeleton_instance::animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const mat4& parent ) 
 {
 	// TODO: fix transforms, which are now embedded,
 	//       see note in assimp_loader.cc:load_node
-	const data_channel_set* node = ( *m_data )[id];
+	const data_channel_set* node = ( *node_data )[id];
 	mat4 node_mat( node->get_transform() );
 
 	if ( node->size() > 0 )
 	{
-		raw_channel_interpolator interpolator( node, m_key );
+		raw_channel_interpolator interpolator( node, binding.m_key );
 		node_mat = interpolator.get< mat4 >( frame );
 	}
@@ -86,13 +82,32 @@
 	mat4 global_mat = parent * node_mat;
 
-	sint16 bone_id = m_indices[id];
+	sint16 bone_id = binding.m_indices[id];
 	if ( bone_id >= 0 )
 	{
-		data[bone_id] = global_mat * m_offsets[bone_id];
+		m_transform[bone_id] = global_mat * binding.m_offsets[bone_id];
 	}
 
-	for ( auto child : m_data->children( id ) )
+	for ( auto child : node_data->children( id ) )
 	{
-		animate_rec( data, frame, child, global_mat );
+		animate_rec( node_data, binding, frame, child, global_mat );
 	}
 }
+
+void nv::skeleton_instance::animate_flat( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame ) 
+{
+	for ( uint32 n = 0; n < node_data->size(); ++n )
+		if ( binding.m_indices[n] >= 0 )
+		{
+			const data_channel_set* node = ( *node_data )[n];
+			nv::mat4 node_mat( node->get_transform() );
+
+			if ( node->size() > 0 )
+			{
+				raw_channel_interpolator interpolator( node, binding.m_key );
+				node_mat = interpolator.get< mat4 >( frame );
+			}
+
+			sint16 bone_id = binding.m_indices[n];
+			m_transform[bone_id] = node_mat * binding.m_offsets[bone_id];
+		}
+}
