Index: trunk/nv/core/resource.hh
===================================================================
--- trunk/nv/core/resource.hh	(revision 476)
+++ trunk/nv/core/resource.hh	(revision 477)
@@ -73,4 +73,5 @@
 		resource() : m_id(0), m_handler( nullptr ) {}
 		bool is_valid() const { return m_id.valid() && m_handler != nullptr;  }
+		resource_id id() const { return m_id; }
 		~resource()
 		{
Index: trunk/nv/engine/program_manager.hh
===================================================================
--- trunk/nv/engine/program_manager.hh	(revision 476)
+++ trunk/nv/engine/program_manager.hh	(revision 477)
@@ -20,5 +20,5 @@
 {
 
-	class program_manager : public resource_manager< program >
+	class program_manager : public lua_resource_manager< program, false >
 	{
 	public:
@@ -27,7 +27,7 @@
 		virtual string_view get_resource_name() const { return "program"; }
 	protected:
-		virtual res_id load_resource( lua::table_guard& table );
+		virtual bool load_resource( lua::table_guard& table, shash64 id );
 		string_buffer load_source( lua::table_guard& table, const string_view& append );
-		virtual void release( program* p );
+		virtual void release( program p );
 	private:
 		context* m_context;
Index: trunk/nv/engine/resource_system.hh
===================================================================
--- trunk/nv/engine/resource_system.hh	(revision 476)
+++ trunk/nv/engine/resource_system.hh	(revision 477)
@@ -24,53 +24,70 @@
 {
 
-	typedef uint32 res_id;
-	typedef uint32 res_type_id;
+	template < typename T, bool Heap = true >
+	struct resource_storage_policy;
+
+	template < typename T >
+	struct resource_storage_policy< T, true >
+	{
+		typedef T* type;
+		static void free( T* value ) { delete value; }
+		static T* to_pointer( T* value ) { return value; }
+	};
+
+	template < typename T >
+	struct resource_storage_policy< T, false >
+	{
+		typedef T type;
+		static void free( T ) {}
+		static T* to_pointer( T& value ) { return &value; }
+	};
 
 	class resource_system;
 
-	class resource_manager_base : public resource_handler
+	class custom_resource_manager_base : public resource_handler
 	{
-	public:	
-		resource_manager_base() : m_lua( nullptr ) {}
+	public:
+		custom_resource_manager_base() {}
+		virtual void clear() = 0;
+		virtual bool load_resource( const string_view& id ) = 0;
+	protected:
+		virtual void unlock( resource_id, resource_type_id ) {};
+		virtual void release( resource_id, resource_type_id ) {};
+	};
+
+	class lua_resource_manager_base : public resource_handler
+	{
+	public:
+		lua_resource_manager_base() : m_lua( nullptr ) {}
 		void initialize( lua::state* state );
 		virtual string_view get_storage_name() const = 0;
 		virtual string_view get_resource_name() const = 0;
-		virtual void clear() { m_names.clear(); }
+		virtual void clear() = 0;
 		void load_all();
-		res_id load_resource( const string_view& id );
-		virtual ~resource_manager_base() {}
+		bool load_resource( const string_view& id );
+		virtual ~lua_resource_manager_base() {}
 	protected:
-		virtual res_id load_resource( lua::table_guard& table ) = 0;
-
-//		virtual const void* lock( resource_id id, resource_type_id );
+		virtual bool load_resource( lua::table_guard& table, shash64 id ) = 0;
+		//		virtual const void* lock( resource_id id, resource_type_id );
 		virtual void unlock( resource_id, resource_type_id ) {};
 		virtual void release( resource_id, resource_type_id ) {};
 
 		lua::state* m_lua;
-		hash_store< shash64, res_id > m_names;
 	};
 
-	template < typename T >
-	class resource_manager : public resource_manager_base
+	template < typename T, bool Heap = true, typename Base = custom_resource_manager_base >
+	class custom_resource_manager : public Base
 	{
 	public:
-		resource_manager() { m_data.push_back(nullptr); }
-		T* get_resource( res_id id )
+		typedef resource_storage_policy< T, Heap > policy_type;
+		typedef T                          value_type;
+		typedef resource< T >              resource_type;
+		typedef typename policy_type::type stored_type;
+
+		custom_resource_manager() {}
+		resource_type get( const string_view& id )
 		{
-			return ( id < m_data.size() ? m_data[ id ] : nullptr );
-		}
-		T* get_resource( const string_view& id )
-		{
-			auto m = m_names.find( id );
-			if ( m != m_names.end() )
-			{
-				return get_resource( m->second );
-			}
-			return get_resource( load_resource( id ) );
-		}
-		resource< T > get( const string_view& id )
-		{
-			auto m = m_names.find( id );
-			if ( m != m_names.end() )
+			auto m = m_store.find( id );
+			if ( m != m_store.end() )
 			{
 				return create< T >( id );
@@ -78,22 +95,36 @@
 			else
 			{
-				if ( get_resource( id ) != nullptr )
+				if ( this->load_resource( id ) )
 				{
 					return create< T >( id );
 				}
 			}
-//			NV_ASSERT( false, "resource_manager.get failed!" );
-			return resource<T>();
+			// NV_ASSERT( false, "resource_manager.get failed!" );
+			return resource_type();
 		}
+
+		resource_type get( uint64 id )
+		{
+			auto m = m_store.find( shash64( id ) );
+			if ( m != m_store.end() )
+			{
+				return create< T >( shash64( id ) );
+			}
+			// NV_ASSERT( false, "resource_manager.get failed!" );
+			return resource_type();
+		}
+
+
 		virtual void clear()
 		{
-			resource_manager_base::clear();
-			for ( uint32 i = 1; i < m_data.size(); ++i )
-				release( m_data[i] );
-			m_data.clear();
-			m_data.push_back( nullptr );
+			for ( auto data : m_store )
+			{
+				release( data.second );
+				policy_type::free( data.second );
+			}
+			m_store.clear();
 		}
 
-		virtual ~resource_manager() 
+		virtual ~custom_resource_manager()
 		{
 			clear();
@@ -102,23 +133,21 @@
 		virtual const void* lock( resource_id id, resource_type_id )
 		{
-			auto m = m_names.find( id );
-			if ( m != m_names.end() )
-			{
-				return m_data[m->second];
-			}
-			return nullptr;
+			auto m = m_store.find( id );
+			return m != m_store.end() ? policy_type::to_pointer( m->second ) : nullptr;
 		}
 
-		virtual void release( T* ) {}
+		virtual void release( stored_type ) {}
 
-		res_id add( T* resource )
+		void add( stored_type resource, shash64 id )
 		{
-			m_data.push_back( resource );
-			return m_data.size() - 1;
+			m_store[id] = resource;
 		}
 
-		vector< T* > m_data;
+		hash_store< shash64, stored_type > m_store;
 	};
-	
+
+	template < typename T, bool Heap = true >
+	using lua_resource_manager = custom_resource_manager< T, Heap, lua_resource_manager_base >;
+
 }
 
Index: trunk/nv/gfx/skeletal_mesh.hh
===================================================================
--- trunk/nv/gfx/skeletal_mesh.hh	(revision 476)
+++ trunk/nv/gfx/skeletal_mesh.hh	(revision 477)
@@ -20,22 +20,16 @@
  	{
 	public:
-		skeletal_animation_entry( shash64 name, const mesh_nodes_data* anim, bool a_looping )
-			: animation_entry( name, a_looping, anim->get_fps(), 0, anim->get_frame_count() )
-			, m_data( anim )
+		skeletal_animation_entry( shash64 name, const mesh_nodes_data* anim, uint32 fps, uint32 time_start, uint32 time_end, bool a_looping )
+			: animation_entry( name, a_looping, fps, time_start, time_end )
+			, m_temp_anim( anim )
 		{
 		}
-
-		skeletal_animation_entry( shash64 name, const mesh_nodes_data* anim, uint32 time_start, uint32 time_end, bool a_looping )
-			: animation_entry( name, a_looping, anim->get_fps(), time_start, time_end )
-			, m_data( anim )
-
-		{
-		}
-
+		const skeleton_binding& get_binding() const { return m_data; }
 		void prepare( const mesh_nodes_data* bones );
-		void update_skeleton( mat4* tr, uint32 a_ms_time ) const;
+		void update_skeleton( skeleton_instance& tr, uint32 a_ms_time ) const;
 		
 	protected:
-		skeleton_instance m_data;
+		const mesh_nodes_data* m_temp_anim;
+		skeleton_binding m_data;
  	};
 
@@ -46,26 +40,27 @@
 		virtual vertex_array get_vertex_array() const { return m_va; }
 		virtual size_t get_index_count() const { return m_index_count; }
-		virtual void run_animation( animation_entry* a_anim )
+		virtual void run_animation( animation_entry& a_anim )
 		{
 			update_animation( a_anim, 0 );
 		}
-		virtual void update( program a_program );
-		virtual void update_animation( animation_entry* a_anim, uint32 a_anim_time );
+		virtual void update_program( program a_program );
+		virtual void update_animation( animation_entry& a_anim, uint32 a_anim_time );
 		virtual transform get_node_transform( uint32 node_id ) const;
 		virtual mat4 get_node_matrix( uint32 node_id ) const;
 		virtual sint16 get_parent_id() const { return m_parent_id; }
-		virtual uint32 get_node_count() const { return m_bone_data ? m_bone_data->size() : 0; }
+		virtual uint32 get_node_count() const { return m_skeleton.size(); }
+		skeleton_instance& get_skeleton() { return m_skeleton; }
+		const mesh_nodes_data* get_bone_data() { return m_bone_data; }
+		context* get_context() { return m_context;  }
 		~skeletal_mesh()
 		{
 			m_context->release( m_va );
-			delete[] m_transform;
 		}
 	protected:
+		skeleton_instance m_skeleton;
 		vertex_array m_va;
+		uint32       m_index_count;
 		context*     m_context;
-		data_descriptor m_interpolation_key;
 		const mesh_nodes_data* m_bone_data;
-		uint32 m_index_count;
-		mat4*  m_transform;
 		sint16 m_parent_id;
 	};
Index: trunk/nv/gfx/skeleton_instance.hh
===================================================================
--- trunk/nv/gfx/skeleton_instance.hh	(revision 476)
+++ trunk/nv/gfx/skeleton_instance.hh	(revision 477)
@@ -9,4 +9,5 @@
 
 #include <nv/common.hh>
+#include <nv/stl/array.hh>
 #include <nv/interface/context.hh>
 #include <nv/interface/mesh_data.hh>
@@ -15,16 +16,14 @@
 {
 
-	class skeleton_instance
+	class skeleton_binding
 	{
 	public:
-		explicit skeleton_instance( const mesh_nodes_data* data )
-			: m_data( data )
-			, m_indices( nullptr )
+		explicit skeleton_binding()
+			: m_indices( nullptr )
 			, m_offsets( nullptr )
 		{
 		}
-		void prepare( const mesh_nodes_data* data );
-		void animate( mat4* data, float frame ) const;
-		~skeleton_instance()
+		void prepare( const mesh_nodes_data* node_data, const mesh_nodes_data* bone_data );
+		~skeleton_binding()
 		{
 			delete[] m_indices;
@@ -32,12 +31,34 @@
 		}
 	protected:
-		void animate_rec( mat4* data, float frame, uint32 id, const mat4& parent ) const;
-		void animate_flat( mat4* data, float frame ) const;
-
-		const mesh_nodes_data* m_data;
 		sint16*                m_indices;
 		mat4*                  m_offsets;
 		data_descriptor        m_key;
+
+		friend class skeleton_instance;
 	};
+
+	class skeleton_instance
+	{
+	public:
+		explicit skeleton_instance( uint32 bone_count )
+		{
+			initialize( bone_count );
+		}
+		void initialize( uint32 bone_count )
+		{
+			if ( bone_count > m_transform.size() )
+				m_transform.resize( bone_count );
+		}
+		const mat4* transforms() const { return m_transform.data(); }
+		size_t size() const { return m_transform.size(); }
+
+		void animate( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame );
+	protected:
+		void animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const mat4& parent );
+		void animate_flat( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame );
+
+		dynamic_array< mat4 > m_transform;
+};
+
 
 }
Index: trunk/nv/interface/animated_mesh.hh
===================================================================
--- trunk/nv/interface/animated_mesh.hh	(revision 476)
+++ trunk/nv/interface/animated_mesh.hh	(revision 477)
@@ -56,6 +56,6 @@
 	public:
 		animated_mesh() {}
-		virtual void update_animation( animation_entry*, uint32 ) {}
-		virtual void run_animation( animation_entry* ) {}
+		virtual void update_animation( animation_entry&, uint32 ) {}
+		virtual void run_animation( animation_entry& ) {}
 		virtual transform get_node_transform( uint32 ) const { return transform(); }
 		virtual mat4 get_node_matrix( uint32 ) const { return mat4(); }
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 476)
+++ trunk/nv/interface/context.hh	(revision 477)
@@ -49,5 +49,5 @@
 	public:
 		mesh_interface() {}
-		virtual void update( program ) {}
+		virtual void update_program( program ) {}
 		virtual nv::vertex_array get_vertex_array() const = 0;
 		virtual size_t get_index_count() const = 0;
Index: trunk/nv/interface/mesh_data.hh
===================================================================
--- trunk/nv/interface/mesh_data.hh	(revision 476)
+++ trunk/nv/interface/mesh_data.hh	(revision 477)
@@ -97,4 +97,13 @@
 		}
 
+		bool is_animated() const
+		{
+			for ( auto data : m_data )
+			{
+				if ( data->size() > 0 ) return true;
+			}
+			return false;
+		}
+
 		const data_channel_set* get_by_hash( shash64 h ) const
 		{
@@ -168,4 +177,6 @@
 		}
 		uint32 get_count() const { return m_count; }
+		data_channel_set* release_meshes() { data_channel_set* meshes = m_meshes; m_meshes = nullptr; return meshes; }
+		mesh_nodes_data* release_nodes() { mesh_nodes_data* nodes = m_nodes; m_nodes = nullptr; return nodes; }
 		const mesh_nodes_data* get_nodes() const { return m_nodes; }
 		uint32 get_node_count() const { return m_nodes ? m_nodes->size() : 0; }
Index: trunk/src/engine/program_manager.cc
===================================================================
--- trunk/src/engine/program_manager.cc	(revision 476)
+++ 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 476)
+++ 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 476)
+++ 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 476)
+++ 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 476)
+++ 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 );
