Index: trunk/src/engine/program_manager.cc
===================================================================
--- trunk/src/engine/program_manager.cc	(revision 475)
+++ trunk/src/engine/program_manager.cc	(revision 477)
@@ -16,5 +16,5 @@
 }
 
-nv::res_id nv::program_manager::load_resource( lua::table_guard& table )
+bool nv::program_manager::load_resource( lua::table_guard& table, shash64 id )
 {
 	NV_LOG_DEBUG( table.get_string("id") );
@@ -36,12 +36,11 @@
 	}
 
-	nv::program* program = new nv::program( m_context->get_device()->create_program( vsource, fsource ) );
-	return add( program );
+	add( m_context->get_device()->create_program( vsource, fsource ), id );
+	return true;
 }
 
-void nv::program_manager::release( program* p )
+void nv::program_manager::release( program p )
 {
-	m_context->get_device()->release( *p );
-	delete p;
+	m_context->get_device()->release( p );
 }
 
Index: trunk/src/engine/resource_system.cc
===================================================================
--- trunk/src/engine/resource_system.cc	(revision 475)
+++ trunk/src/engine/resource_system.cc	(revision 477)
@@ -9,5 +9,5 @@
 #include "nv/lua/lua_nova.hh"
 
-void nv::resource_manager_base::initialize( lua::state* a_lua_state )
+void nv::lua_resource_manager_base::initialize( lua::state* a_lua_state )
 {
 	m_lua = a_lua_state;
@@ -16,13 +16,12 @@
 }
 
-nv::res_id nv::resource_manager_base::load_resource( const string_view& id )
+bool nv::lua_resource_manager_base::load_resource( const string_view& id )
 {
 	lua::table_guard table( m_lua, lua::path( get_storage_name(), id ) );
-	res_id rid = load_resource( table );
-	if ( rid != 0 ) m_names[ id ] = rid;
-	return rid;
+	load_resource( table, id );
+	return true;
 }
 
-void nv::resource_manager_base::load_all()
+void nv::lua_resource_manager_base::load_all()
 {
 	clear();
@@ -31,7 +30,7 @@
 	for ( auto i : range( count ) )
 	{
-		lua::table_guard sub_table( table, i+1 );
-		res_id rid = load_resource( sub_table );
-		if ( rid != 0 ) m_names[ sub_table.get_string_hash_64("id") ] = rid;
+		lua::table_guard sub_table( table, i + 1 );
+		load_resource( sub_table, sub_table.get_string_hash_64( "id" ) );
 	}
 }
+
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];
+		}
+}
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 475)
+++ trunk/src/gl/gl_device.cc	(revision 477)
@@ -389,5 +389,5 @@
 		glGetProgramInfoLog( p->glid, buffer_size, &length, buffer );
 		NV_LOG_ERROR( "Program #", p->glid, " validation error : ", buffer );
-		return false;
+		//return false;
 	}
 	load_attributes( p );
