Index: /trunk/nv/formats/assimp_loader.hh
===================================================================
--- /trunk/nv/formats/assimp_loader.hh	(revision 426)
+++ /trunk/nv/formats/assimp_loader.hh	(revision 427)
@@ -31,9 +31,9 @@
 	private:
 		mesh_nodes_data* release_merged_bones( data_channel_set* meshes );
-		bool load_bones( size_t index, array_ref< mesh_node_data > bones );
+		bool load_bones( size_t index, array_ref< data_channel_set* > bones );
 		void load_mesh_data( data_channel_set* data, size_t index );
-		sint16 load_node( uint32 anim_id, mesh_node_data* nodes, const void* vnode, sint16 this_id, sint16 parent_id );
+		sint16 load_node( uint32 anim_id, array_ref< data_channel_set* > nodes, const void* vnode, sint16 this_id, sint16 parent_id );
 		uint32 count_nodes( const void* node ) const;
-		void create_keys( mesh_node_data* data, const void* vnode );
+		data_channel_set* create_keys( const void* vnode );
 
 		const_string m_ext;
Index: /trunk/nv/formats/md5_loader.hh
===================================================================
--- /trunk/nv/formats/md5_loader.hh	(revision 426)
+++ /trunk/nv/formats/md5_loader.hh	(revision 427)
@@ -83,6 +83,6 @@
 	protected:
 		void reset();
-		void build_frame_skeleton( mesh_node_data* nodes, uint32 index, const array_view<md5_joint_info>& joint_info, const array_view<transform>& base_frames, const array_view<float>& frame_data );
-		bool prepare_mesh( mesh_node_data* nodes, uint32 vtx_count, data_channel_set* mdata, md5_weight* weights, md5_weight_info* weight_info );
+		void build_frame_skeleton( mesh_nodes_data* nodes, uint32 index, const array_view<md5_joint_info>& joint_info, const array_view<transform>& base_frames, const array_view<float>& frame_data );
+		bool prepare_mesh( mesh_nodes_data* nodes, uint32 vtx_count, data_channel_set* mdata, md5_weight* weights, md5_weight_info* weight_info );
 	protected:
 		file_type m_type;
Index: /trunk/nv/formats/nmd_loader.hh
===================================================================
--- /trunk/nv/formats/nmd_loader.hh	(revision 426)
+++ /trunk/nv/formats/nmd_loader.hh	(revision 427)
@@ -78,5 +78,5 @@
 	{
 	public:
-		explicit nmd_loader( string_table* strings ) : mesh_loader( strings ), m_node_data( nullptr ), m_node_array( nullptr ) {}
+		explicit nmd_loader( string_table* strings ) : mesh_loader( strings ), m_node_data( nullptr ) {}
 		virtual bool load( stream& source );
 		virtual data_channel_set* release_mesh_data( size_t index = 0 );
@@ -92,12 +92,8 @@
 		bool load_strings( stream& source ); 
 		bool load_animation( stream& source, const nmd_element_header& e );
-		bool load_node( stream& source, mesh_node_data* data, const nmd_element_header& e );
 		bool load_channel( stream& source, data_channel_set* channel_set );
 		bool load_channel_set( stream& source, data_channel_set* channel_set, const nmd_element_header& e );
 
 		mesh_nodes_data*            m_node_data;
-		mesh_node_data*             m_node_array;
-//		vector< uint16 >            m_mesh_names;
-//		vector< uint16 >            m_node_names;
 		vector< data_channel_set* > m_meshes;
 	};
@@ -106,5 +102,5 @@
 	void nmd_dump_header( stream& stream_out, uint32 elements, uint64 name );
 	void nmd_dump_strings( stream& stream_out, const string_table& strings );
-	void nmd_dump_mesh( stream& stream_out, const data_channel_set& mesh );
+	void nmd_dump_element( stream& stream_out, const data_channel_set& data, nmd_type type );
 	void nmd_dump_nodes( stream& stream_out, const mesh_nodes_data& nodes );
 	void nmd_dump( stream& stream_out, const mesh_data_pack* model, const string_table* strings = nullptr, uint64 name = 0 );
Index: /trunk/nv/interface/data_channel_access.hh
===================================================================
--- /trunk/nv/interface/data_channel_access.hh	(revision 426)
+++ /trunk/nv/interface/data_channel_access.hh	(revision 427)
@@ -141,20 +141,4 @@
 		const_iterator end()   const { return m_set->end(); }
 
-		void move_to( data_channel_set& other )
-		{
-			int change_to_move;
-			//			other.m_name          = m_name;
-			for ( uint32 c = 0; c < m_set->m_size; ++c )
-			{
-//				if ( other.m_channels[c] ) delete other.m_channels[c];
-				other.m_channels[c] = move( m_set->m_channels[c] );
-			}
-			other.m_name = m_set->m_name;
-			other.m_parent_id = m_set->m_parent_id;
-			other.m_transform = m_set->m_transform;
-			other.m_size = m_set->m_size;
-			m_set->m_size = 0;
-		}
-
 		void set_transform( const mat4& tr ) { m_set->m_transform = tr; }
 		const mat4& get_transform() const { return m_set->m_transform; }
Index: /trunk/nv/interface/mesh_data.hh
===================================================================
--- /trunk/nv/interface/mesh_data.hh	(revision 426)
+++ /trunk/nv/interface/mesh_data.hh	(revision 427)
@@ -22,15 +22,5 @@
 	using mesh_data = data_channel_set;
 
-#pragma warning TODO_LIST!
-	// TODO : 
-	//  * get rid of mesh_node_data, optimize further
-	//  * properly write and read strings from nmd's
-	//  * mesh_loader string_table support
-	//  * properly write strings in other loaders
-	//  * attribute/property implementation and read/write on every nmd::command
-	struct mesh_node_data
-	{
-		data_channel_set* data;
-	};
+	// TODO : attribute/property implementation and read/write on every nmd::command
 
 	class mesh_nodes_data
@@ -39,36 +29,41 @@
 		friend class mesh_nodes_creator;
 	public:
-		explicit mesh_nodes_data( uint64 name, uint32 count, mesh_node_data* nodes )
-			: m_name( name ), m_count( count ), m_nodes( nodes ), m_frame_rate(0), m_duration(0.0f), m_flat( false )
+		typedef vector< data_channel_set* > storage;
+		typedef storage::const_iterator const_iterator;
+
+		explicit mesh_nodes_data( uint64 name )
+			: m_name( name ), m_frame_rate(0), m_duration(0.0f), m_flat( false )
 		{
 		}
 
-		explicit mesh_nodes_data( uint64 name, uint32 count, mesh_node_data* nodes,
-			uint16 a_fps, float a_frames, bool a_flat )
-			: m_name( name ), m_count( count ), m_nodes( nodes ), m_frame_rate(a_fps), m_duration(a_frames), m_flat( a_flat )
+		explicit mesh_nodes_data( uint64 name, uint16 a_fps, float a_frames, bool a_flat )
+			: m_name( name ), m_frame_rate(a_fps), m_duration(a_frames), m_flat( a_flat )
 		{
 		}
 
-		size_t get_count() const { return m_count; }
+		void push_back( data_channel_set* set )
+		{
+			m_data.push_back( set );
+		}
+
+		size_t get_count() const { return m_data.size(); }
 
 		bool is_animated( size_t i ) const
 		{
-			if ( i >= m_count ) return false;
-			return ( m_nodes[i].data && m_nodes[i].data->size() > 0 );
+			if ( i >= m_data.size() ) return false;
+			return ( m_data[i]->size() > 0 );
 		}
 
-		const mesh_node_data* get_node( size_t i ) const 
+		const data_channel_set* get_node( size_t i ) const
 		{
-			if ( i >= m_count ) return nullptr;
-			return &m_nodes[i];
+			if ( i >= m_data.size() ) return nullptr;
+			return m_data[i];
 		}
 
-		const mesh_node_data* get_node_by_hash( uint64 h ) const
+		const data_channel_set* get_node_by_hash( uint64 h ) const
 		{
-			for ( uint32 i = 0; i < m_count; ++i )
+			for ( auto data : m_data )
 			{
-				NV_ASSERT( m_nodes[i].data, "data!" );
-				if ( m_nodes[ i ].data->get_name() == h )
-					return &m_nodes[ i ];
+				if ( data->get_name() == h ) return data;
 			}
 			return nullptr;
@@ -77,8 +72,7 @@
 		int get_node_index_by_hash( uint64 h ) const
 		{
-			for ( uint32 i = 0; i < m_count; ++i )
+			for ( uint32 i = 0; i < m_data.size(); ++i )
 			{
-				NV_ASSERT( m_nodes[i].data, "data!" );
-				if ( m_nodes[ i ].data->get_name() == h )
+				if ( m_data[ i ]->get_name() == h )
 					return int( i );
 			}
@@ -86,10 +80,11 @@
 		}
 
-// 		data_channel_set* rlease_node_data( size_t i )
-// 		{
-// 			data_channel_set* result = m_nodes[i].data;
-// 			m_nodes[i].data = nullptr;
-// 			return result;
-// 		}
+		const data_channel_set* operator[]( size_t i ) const
+		{
+			return m_data[i];
+		}
+
+		const_iterator begin() const { return m_data.begin(); }
+		const_iterator end() const { return m_data.end(); }
 
 		bool is_flat() const { return m_flat; }
@@ -101,13 +96,10 @@
 		~mesh_nodes_data()
 		{
-			if ( m_count > 0 )
-				for ( uint32 i = 0; i < m_count; ++i ) delete m_nodes[i].data;
-			delete[] m_nodes;
+			for ( auto data : m_data ) delete data;
 		}
 
 	private:
+		vector< data_channel_set* > m_data;
 		uint64 m_name;
-		uint32 m_count;
-		mesh_node_data* m_nodes;
 		uint16  m_frame_rate;
 		float   m_duration;
Index: /trunk/nv/stl/memory.hh
===================================================================
--- /trunk/nv/stl/memory.hh	(revision 426)
+++ /trunk/nv/stl/memory.hh	(revision 427)
@@ -137,5 +137,5 @@
 
 		constexpr size_type size() const { return m_size; }
-		constexpr bool empty() const { return m_size != 0; }
+		constexpr bool empty() const { return m_size == 0; }
 		constexpr const value_type* data() const { return m_data; }
 		constexpr size_type   raw_size() const { return sizeof( value_type ) * m_size; }
Index: /trunk/src/formats/assimp_loader.cc
===================================================================
--- /trunk/src/formats/assimp_loader.cc	(revision 426)
+++ /trunk/src/formats/assimp_loader.cc	(revision 427)
@@ -190,5 +190,5 @@
 }
 
-bool nv::assimp_loader::load_bones( size_t index, array_ref< mesh_node_data > bones )
+bool nv::assimp_loader::load_bones( size_t index, array_ref< data_channel_set* > bones )
 {
 	if ( m_scene == nullptr ) return false;
@@ -200,6 +200,6 @@
 		aiBone* bone   = mesh->mBones[m];
 		mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix );
-		bones[m].data = data_channel_set_creator::create_set( 0 );
-		data_channel_set_creator access( bones[m].data );
+		bones[m] = data_channel_set_creator::create_set( 0 );
+		data_channel_set_creator access( bones[m] );
 		const char* name = bone->mName.data;
 		access.set_name( make_name( name ) );
@@ -287,10 +287,10 @@
 {
 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
-	vector< mesh_node_data > final_bones;
+	mesh_nodes_data* result = new mesh_nodes_data( make_name( "bones" ) );
 	unordered_map< uint64, uint16 > names;
 	for ( unsigned int m = 0; m < m_mesh_count; ++m )
 	{
 		uint16 translate[MAX_BONES];
-		vector< mesh_node_data > bones;
+		vector< data_channel_set* > bones;
 		const aiMesh*  mesh  = scene->mMeshes[ m ];
 		if ( mesh->mNumBones != 0 )
@@ -301,12 +301,12 @@
 			{
 
-				mesh_node_data& bone = bones[b];
-				auto iname = names.find( bone.data->get_name() );
+				data_channel_set* bone = bones[b];
+				auto iname = names.find( bone->get_name() );
 				if ( iname == names.end() )
 				{
-					NV_ASSERT( final_bones.size() < MAX_BONES, "Too many bones to merge!" );
-					uint16 index = uint16( final_bones.size() );
-					final_bones.push_back( bone );
-					names[ bone.data->get_name() ] = index;
+					NV_ASSERT( result->get_count() < MAX_BONES, "Too many bones to merge!" );
+					uint16 index = uint16( result->get_count() );
+					result->push_back( bone );
+					names[ bone->get_name() ] = index;
 					translate[b] = index;
 				}
@@ -334,7 +334,6 @@
 		}	
 	}
-	mesh_node_data* bones = new mesh_node_data[ final_bones.size() ];
-	raw_copy( final_bones.begin(), final_bones.end(), bones );
-	return new mesh_nodes_data( make_name( "bones" ), final_bones.size(), bones );
+
+	return result;
 }
 
@@ -349,5 +348,4 @@
 
 	uint32 count = count_nodes( scene->mRootNode );
-	mesh_node_data* data    = new mesh_node_data[count];
 
 	uint16 frame_rate     = static_cast<uint16>( anim->mTicksPerSecond );
@@ -355,7 +353,15 @@
 	bool   flat           = false;
 
-	load_node( index, data, root, 0, -1 );
-
-	return new mesh_nodes_data( make_name( static_cast<const char*>( anim->mName.data ) ), count, data, frame_rate, duration, flat );
+	data_channel_set** temp = new data_channel_set*[ count ];
+	array_ref< data_channel_set* > temp_ref( temp, count );
+	load_node( index, temp_ref, root, 0, -1 );
+
+	mesh_nodes_data* result = new mesh_nodes_data( make_name( static_cast<const char*>( anim->mName.data ) ), frame_rate, duration, flat );
+	for ( auto set : temp_ref )
+	{
+		result->push_back( set );
+	}
+	delete temp;
+	return result;
 }
 
@@ -371,5 +377,5 @@
 }
 
-nv::sint16 nv::assimp_loader::load_node( uint32 anim_id, mesh_node_data* nodes, const void* vnode, sint16 this_id, sint16 parent_id )
+nv::sint16 nv::assimp_loader::load_node( uint32 anim_id, array_ref< data_channel_set* > nodes, const void* vnode, sint16 this_id, sint16 parent_id )
 {
 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
@@ -386,12 +392,7 @@
 	}
 
-	mesh_node_data& a_data = nodes[ this_id ];
-
-	if (anode) 
-		create_keys( &a_data, anode );
-	else
-		a_data.data = data_channel_set_creator::create_set( 0 );
-
-	data_channel_set_creator access( a_data.data );
+	nodes[ this_id ] = anode ? create_keys( anode ) : data_channel_set_creator::create_set( 0 );
+
+	data_channel_set_creator access( nodes[this_id] );
 	access.set_name( make_name( name ) );
 	access.set_parent_id( parent_id );
@@ -412,14 +413,14 @@
 }
 
-void nv::assimp_loader::create_keys( mesh_node_data* data, const void* vnode )
+data_channel_set* nv::assimp_loader::create_keys( const void* vnode )
 {
 	const aiNodeAnim* node = reinterpret_cast< const aiNodeAnim* >( vnode );
 	if ( node->mNumPositionKeys == 0 && node->mNumRotationKeys == 0 && node->mNumScalingKeys == 0 )
 	{
-		return;
-	}
-
-	data->data = data_channel_set_creator::create_set( 2 );
-	data_channel_set_creator key_set( data->data );
+		return data_channel_set_creator::create_set( 0 );
+	}
+	
+	data_channel_set* set = data_channel_set_creator::create_set( 2 );
+	data_channel_set_creator key_set( set );
 
 	assimp_key_p* pchannel = key_set.add_channel< assimp_key_p >( node->mNumPositionKeys ).data();
@@ -456,5 +457,5 @@
 // 		}
 // 	}
-
+	return set;
 }
 
Index: /trunk/src/formats/md3_loader.cc
===================================================================
--- /trunk/src/formats/md3_loader.cc	(revision 426)
+++ /trunk/src/formats/md3_loader.cc	(revision 427)
@@ -420,15 +420,16 @@
 	uint32 node_count = uint32( md3->header.num_tags );
 	if ( node_count == 0 ) return nullptr;
-	mesh_node_data* nodes = new mesh_node_data[ node_count ];
+	mesh_nodes_data* result = new mesh_nodes_data( m_strings ? m_strings->insert( "tags" ) : 0 );
 	for ( uint32 i = 0; i < node_count; ++i )
 	{
 		const md3_tag_t& rtag = md3->tags[i];
 		string_view name( reinterpret_cast< const char* >(rtag.name) );
-		nodes[i].data      = data_channel_set_creator::create_set( 1 );
-		data_channel_set_creator access( nodes[i].data );
+		data_channel_set* set = data_channel_set_creator::create_set( 1 );
+		data_channel_set_creator access( set );
 		access.set_name( make_name( name ) );
 		load_tags( access.add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
-	}
-	return new mesh_nodes_data( m_strings ? m_strings->insert( "tags" ) : 0, node_count, nodes );
+		result->push_back( set );
+	}
+	return result;
 }
 
Index: /trunk/src/formats/md5_loader.cc
===================================================================
--- /trunk/src/formats/md5_loader.cc	(revision 426)
+++ /trunk/src/formats/md5_loader.cc	(revision 427)
@@ -46,5 +46,4 @@
 	std_stream sstream( &source );
 	std::string command;
-	mesh_node_data* nodes = nullptr;
 	size_t num_joints = 0;
 
@@ -111,6 +110,5 @@
 			assert( m_type == MESH );
 			assert( m_nodes == nullptr );
-			nodes = new mesh_node_data[ num_joints ];
-			m_nodes = new mesh_nodes_data( make_name( "md5_bones"), num_joints, nodes );
+			m_nodes = new mesh_nodes_data( make_name( "md5_bones") );
 			discard( sstream, "{" );
 			for ( size_t i = 0; i < m_nodes->get_count(); ++i )
@@ -128,10 +126,11 @@
 				unit_quat_w( orient );
 				remove_quotes( name );
-				nodes[i].data       = data_channel_set_creator::create_set( 0 );
-				data_channel_set_creator access( nodes[i].data );
+				data_channel_set* set = data_channel_set_creator::create_set( 0 );
+				data_channel_set_creator access( set );
 				access.set_parent_id( parent_id );
 				access.set_transform( transform( pos, orient ).inverse().extract() );
 				access.set_name( make_name( name.c_str() ) );
 				next_line( sstream );
+				m_nodes->push_back( set );
 			}
 			discard( sstream, "}" );
@@ -233,5 +232,5 @@
 			}
 
-			prepare_mesh( nodes, weight_info.size(), mesh, weights.data(), weight_info.data() );
+			prepare_mesh( m_nodes, weight_info.size(), mesh, weights.data(), weight_info.data() );
 
 			m_meshes[ num_meshes ] = mesh;
@@ -241,7 +240,6 @@
 		{
 			assert( m_type == ANIMATION );
-			assert( nodes == nullptr );
-			nodes = new mesh_node_data[ num_joints ];
-			m_nodes = new mesh_nodes_data( make_name( "md5_animation" ), num_joints, nodes, static_cast< nv::uint16 >( frame_rate ), static_cast< float >( num_frames ), true );
+			assert( m_nodes == nullptr );
+			m_nodes = new mesh_nodes_data( make_name( "md5_animation" ), static_cast< nv::uint16 >( frame_rate ), static_cast< float >( num_frames ), true );
 			joint_infos.resize( num_joints );
 
@@ -253,9 +251,10 @@
 				sstream >> name >> parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
 				remove_quotes( name );
-				nodes[i].data = data_channel_set_creator::create_set( 1 );
-				data_channel_set_creator access( nodes[i].data );
+				data_channel_set* set = data_channel_set_creator::create_set( 1 );
+				data_channel_set_creator access( set );
 				access.add_channel< md5_key_t >( num_frames );
 				access.set_name( make_name( name.c_str() ) );
 				access.set_parent_id( parent_id );
+				m_nodes->push_back( set );
 				next_line( sstream );
 			}
@@ -322,5 +321,5 @@
 			}
 
-			build_frame_skeleton( nodes, frame_id, joint_infos, base_frames, frame );
+			build_frame_skeleton( m_nodes, frame_id, joint_infos, base_frames, frame );
 
 			discard( sstream, "}" );
@@ -334,5 +333,5 @@
 }
 
-bool md5_loader::prepare_mesh( mesh_node_data* nodes, uint32 vtx_count, data_channel_set* mdata, md5_weight* weights, md5_weight_info* weight_info )
+bool md5_loader::prepare_mesh( mesh_nodes_data* nodes, uint32 vtx_count, data_channel_set* mdata, md5_weight* weights, md5_weight_info* weight_info )
 {
 	assert( m_type == MESH );
@@ -389,7 +388,7 @@
 			if ( j < weight_count )
 			{
-				md5_weight& weight           = weights[start_weight + j];
-				const mesh_node_data&  joint = nodes[weight.joint_id];
-				const transform tr = transform( joint.data->get_transform() ).inverse();
+				md5_weight& weight             = weights[start_weight + j];
+				const data_channel_set*  joint = (*nodes)[weight.joint_id];
+				const transform tr = transform( joint->get_transform() ).inverse();
 				vec3 rot_pos = tr.get_orientation() * weight.pos;
 
@@ -453,6 +452,6 @@
  		for ( int j = 0; j < 4; ++j )
  		{
-			const mesh_node_data&  joint = nodes[vdata.boneindex[j]];
-			const transform tr = transform( joint.data->get_transform() ).inverse();
+			const data_channel_set*  joint = ( *nodes )[vdata.boneindex[j]];
+			const transform tr = transform( joint->get_transform() ).inverse();
  			vdata.normal  += ( normal  * tr.get_orientation() ) * vdata.boneweight[j];
  			vdata.tangent += ( tangent * tr.get_orientation() ) * vdata.boneweight[j];
@@ -463,5 +462,5 @@
 }
 
-void md5_loader::build_frame_skeleton( mesh_node_data* nodes, uint32 index, const array_view<md5_joint_info>& joint_infos, const array_view<transform>& base_frames, const array_view<float>& frame_data )
+void md5_loader::build_frame_skeleton( mesh_nodes_data* nodes, uint32 index, const array_view<md5_joint_info>& joint_infos, const array_view<transform>& base_frames, const array_view<float>& frame_data )
 {
 	assert( m_type == ANIMATION );
@@ -471,6 +470,6 @@
 
 		const md5_joint_info& jinfo = joint_infos[i];
-		mesh_node_data& joint = nodes[i];
-		int parent_id         = joint.data->get_parent_id();
+		const data_channel_set* joint = (*nodes)[i];
+		int parent_id         = joint->get_parent_id();
 
 		vec3 pos    = base_frames[i].get_position();
@@ -486,8 +485,8 @@
 		if ( parent_id >= 0 ) // Has a parent joint
 		{
-			const mesh_node_data& pjoint = nodes[parent_id];
-			const transform* ptv = reinterpret_cast< const transform* >( pjoint.data->get_channel(0)->raw_data() );
+			const data_channel_set* pjoint = ( *nodes )[i];
+			const transform* ptv = reinterpret_cast< const transform* >( pjoint->get_channel(0)->raw_data() );
 			transform ptr;
-			if ( pjoint.data->get_channel(0)->size() > index ) ptr = ptv[ index ];
+			if ( pjoint->get_channel(0)->size() > index ) ptr = ptv[ index ];
 			vec3 rot_pos = ptr.get_orientation() * pos;
 
@@ -498,5 +497,5 @@
 		}
 
-		reinterpret_cast< transform* >( const_cast< uint8* >( joint.data->get_channel(0)->raw_data() ) )[index] = transform( pos, orient );
+		reinterpret_cast< transform* >( const_cast< uint8* >( joint->get_channel(0)->raw_data() ) )[index] = transform( pos, orient );
 	}
 }
Index: /trunk/src/formats/nmd_loader.cc
===================================================================
--- /trunk/src/formats/nmd_loader.cc	(revision 426)
+++ /trunk/src/formats/nmd_loader.cc	(revision 427)
@@ -71,5 +71,4 @@
 
 	m_node_data  = nullptr;
-	m_node_array = nullptr;
 }
 
@@ -100,5 +99,5 @@
 	nmd_animation_header animation_header;
 	source.read( &animation_header, sizeof( animation_header ), 1 );
-	m_node_array = new mesh_node_data[ e.children ];
+	m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.duration, animation_header.flat );
 	for ( uint32 i = 0; i < e.children; ++i )
 	{
@@ -107,8 +106,8 @@
 		skip_attributes( source, element_header.attributes );
 		NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
-		m_node_array[i].data = data_channel_set_creator::create_set( element_header.children );
-		load_channel_set( source, m_node_array[i].data, element_header );
-	}
-	m_node_data = new mesh_nodes_data( e.name, e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
+		data_channel_set* set = data_channel_set_creator::create_set( element_header.children );
+		load_channel_set( source, set, element_header );
+		m_node_data->push_back( set );
+	}
 	return true;
 }
@@ -144,5 +143,4 @@
 		mesh_nodes_data* result = m_node_data;
 		m_node_data = nullptr;
-		m_node_array = nullptr;
 		return result;
 	}
@@ -153,42 +151,4 @@
 // nmd format dump
 // HACK : TEMPORARY - will go to it's own file, probably nmd_io
-static void nmd_dump_channel( const raw_data_channel* channel , stream& stream_out )
-{
-	nmd_channel_header sheader;
-	sheader.format = channel->descriptor();
-	sheader.count = channel->size();
-	stream_out.write( &sheader, sizeof( sheader ), 1 );
-	stream_out.write( channel->raw_data(), channel->element_size(), channel->size() );
-}
-
-static void nmd_dump_channel_set( const data_channel_set* channel_set, stream& stream_out )
-{
-	for ( auto& channel : *channel_set )
-	{
-		nmd_dump_channel( &channel, stream_out );
-	}
-}
-
-static void nmd_dump_node( const mesh_node_data* node, stream& stream_out )
-{
-	uint32 chan_size = 0;
-	uint32 chan_count = ( node->data ? node->data->size() : 0 );
-	for ( uint32 c = 0; c < chan_count; ++c )
-	{
-		chan_size += sizeof( nmd_channel_header );
-		chan_size += node->data->get_channel( c )->raw_size();
-	}
-
-	nmd_element_header eheader;
-	eheader.type = nmd_type::NODE;
-	eheader.children   = static_cast<uint16>( chan_count );
-	eheader.size       = chan_size;
-	eheader.name       = node->data->get_name();
-	eheader.parent_id  = node->data->get_parent_id();
-	eheader.transform  = node->data->get_transform();
-	eheader.attributes = 0;
-	stream_out.write( &eheader, sizeof( eheader ), 1 );
-	if ( chan_count > 0 ) nmd_dump_channel_set( node->data, stream_out );
-}
 
 void nv::nmd_dump_header( stream& stream_out, uint32 elements, uint64 name )
@@ -203,8 +163,8 @@
 }
 
-void nv::nmd_dump_mesh( stream& stream_out, const data_channel_set& mesh )
+void nv::nmd_dump_element( stream& stream_out, const data_channel_set& data, nmd_type type )
 {
 	uint32 size = 0;
-	for ( auto& chan : mesh )
+	for ( auto& chan : data )
 	{
 		size += sizeof( nmd_channel_header );
@@ -213,13 +173,20 @@
 
 	nmd_element_header eheader;
-	eheader.type       = nmd_type::MESH;
-	eheader.children   = static_cast<uint16>( mesh.size() );
+	eheader.type       = type;
+	eheader.children   = static_cast<uint16>( data.size() );
 	eheader.size       = size;
-	eheader.name       = mesh.get_name();
-	eheader.transform  = mesh.get_transform();
-	eheader.parent_id  = mesh.get_parent_id();
+	eheader.name       = data.get_name();
+	eheader.transform  = data.get_transform();
+	eheader.parent_id  = data.get_parent_id();
 	eheader.attributes = 0;
 	stream_out.write( &eheader, sizeof( eheader ), 1 );
-	nmd_dump_channel_set( &mesh, stream_out );
+	for ( auto& channel : data )
+	{
+		nmd_channel_header cheader;
+		cheader.format = channel.descriptor();
+		cheader.count = channel.size();
+		stream_out.write( &cheader, sizeof( cheader ), 1 );
+		stream_out.write( channel.raw_data(), channel.element_size(), channel.size() );
+	}
 }
 
@@ -227,14 +194,12 @@
 {
 	uint32 total = sizeof( nmd_animation_header );
-	for ( uint32 i = 0; i < nodes.get_count(); ++i )
-	{
-		const mesh_node_data* node = nodes.get_node( i );
+	for ( auto node : nodes )
+	{
 		total += sizeof( nmd_element_header );
-		if ( node->data )
-			for ( uint32 c = 0; c < node->data->size(); ++c )
-			{
-				total += sizeof( nmd_channel_header );
-				total += node->data->get_channel( c )->raw_size();
-			}
+		for ( uint32 c = 0; c < node->size(); ++c )
+		{
+			total += sizeof( nmd_channel_header );
+			total += node->get_channel( c )->raw_size();
+		}
 	}
 
@@ -256,7 +221,7 @@
 	stream_out.write( &aheader, sizeof( aheader ), 1 );
 
-	for ( uint32 i = 0; i < nodes.get_count(); ++i )
-	{
-		nmd_dump_node( nodes.get_node( i ), stream_out );
+	for ( auto node : nodes )
+	{
+		nmd_dump_element( stream_out, *node, nv::nmd_type::NODE );
 	}
 }
@@ -284,5 +249,5 @@
 	for ( uint32 i = 0; i < model->get_count(); ++i )
 	{
-		nmd_dump_mesh( stream_out, *model->get_mesh( i ) );
+		nmd_dump_element( stream_out, *model->get_mesh( i ), nv::nmd_type::MESH );
 	}
 
Index: /trunk/src/formats/obj_loader.cc
===================================================================
--- /trunk/src/formats/obj_loader.cc	(revision 426)
+++ /trunk/src/formats/obj_loader.cc	(revision 427)
@@ -363,5 +363,5 @@
 	for ( uint32 i = 0; i < size; ++i )
 	{
-		data_channel_set_creator( m_meshes[i] ).move_to( meshes[i] );
+		meshes[i] = move( *m_meshes[i] );
 		delete m_meshes[i];
 	}
Index: /trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- /trunk/src/gfx/keyframed_mesh.cc	(revision 426)
+++ /trunk/src/gfx/keyframed_mesh.cc	(revision 427)
@@ -42,5 +42,5 @@
 	if ( m_tag_map && m_tag_map->get_count() > 0 )
 	{
-		m_interpolation_key = m_tag_map->get_node( 0 )->data->get_interpolation_key();
+		m_interpolation_key = (*m_tag_map)[ 0 ]->get_interpolation_key();
 	}
 }
@@ -55,7 +55,6 @@
 	if ( !m_tag_map ) return transform();
 	NV_ASSERT( node_id < m_tag_map->get_count(), "TAGMAP FAIL" );
-	const data_channel_set* data = m_tag_map->get_node( node_id )->data;
-	NV_ASSERT( data && data->size() > 0, "TAG FAIL" );
-	raw_channel_interpolator interpolator( data, m_interpolation_key );
+	NV_ASSERT( (*m_tag_map)[node_id]->size() > 0, "TAG FAIL" );
+	raw_channel_interpolator interpolator( ( *m_tag_map )[node_id], 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 426)
+++ /trunk/src/gfx/mesh_creator.cc	(revision 427)
@@ -18,7 +18,7 @@
 	for ( size_t i = 0; i < m_data->get_count(); ++i )
 	{
-		sint16 parent_id = m_data->m_nodes[i].data->get_parent_id();
-		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 );
+		data_channel_set* keys = m_data->m_data[i];
+		sint16 parent_id = keys->get_parent_id();
+		data_channel_set* pkeys  = ( parent_id != -1 ? m_data->m_data[parent_id] : nullptr );
 		size_t count     = ( keys ? keys->get_channel_size(0) : 0 );
 		size_t pcount    = ( pkeys ? pkeys->get_channel_size(0) : 0 );
@@ -51,5 +51,5 @@
 	for ( size_t i = 0; i < m_data->get_count(); ++i )
 	{
-		data_channel_set* old_keys = m_data->m_nodes[i].data;
+		data_channel_set* old_keys = m_data->m_data[i];
 		if ( old_keys && old_keys->size() > 0 )
 		{
@@ -89,5 +89,5 @@
 
 			delete old_keys;
-			m_data->m_nodes[i].data = new_keys;
+			m_data->m_data[i] = new_keys;
 		}
 	}
@@ -102,17 +102,14 @@
 	for ( size_t i = 0; i < m_data->get_count(); ++i )
 	{
-		mesh_node_data& node = m_data->m_nodes[i];
-		node.data->m_transform = pre_transform * node.data->m_transform * post_transform;
-		if ( node.data )
-		{
-			data_channel_set* kdata  = node.data;
-			for ( size_t c = 0; c < kdata->size(); ++c )
-			{
-				raw_data_channel_access channel( kdata, c );
-				size_t key_size = channel.element_size();
-				for ( size_t n = 0; n < channel.size(); ++n )
-				{
-					transform_key_raw( kdata->get_channel( c )->descriptor(), channel.raw_data() + n * key_size, scale, r33, ri33 );
-				}
+		data_channel_set* node = m_data->m_data[i];
+		node->m_transform = pre_transform * node->m_transform * post_transform;
+
+		for ( size_t c = 0; c < node->size(); ++c )
+		{
+			raw_data_channel_access channel( node, c );
+			size_t key_size = channel.element_size();
+			for ( size_t n = 0; n < channel.size(); ++n )
+			{
+				transform_key_raw( node->get_channel( c )->descriptor(), channel.raw_data() + n * key_size, scale, r33, ri33 );
 			}
 		}
@@ -458,5 +455,6 @@
 	if ( index < m_pack->get_count() )
 	{
-		data_channel_set_creator( &m_pack->m_meshes[m_pack->m_count - 1] ).move_to( m_pack->m_meshes[index] );
+
+		m_pack->m_meshes[index] = move( m_pack->m_meshes[m_pack->m_count - 1] );
 		m_pack->m_count--;
 	}
Index: /trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- /trunk/src/gfx/skeletal_mesh.cc	(revision 426)
+++ /trunk/src/gfx/skeletal_mesh.cc	(revision 427)
@@ -23,5 +23,5 @@
 	for ( uint32 i = 0; i < bones->get_count(); ++i )
 	{
-		m_bone_offset[i] = transform( bones->get_node(i)->data->get_transform() );
+		m_bone_offset[i] = transform( (*bones)[i]->get_transform() );
 	}
 
@@ -93,9 +93,9 @@
 void nv::skeletal_animation_entry_cpu::initialize()
 {
-	for ( size_t i = 0; i < m_node_data->get_count(); ++i )
-	{
-		if ( m_node_data->is_animated( i ) )
-		{
-			m_interpolation_key = m_node_data->get_node( i )->data->get_interpolation_key();
+	for ( auto bone : *m_node_data )
+	{
+		if ( bone->size() > 0 )
+		{
+			m_interpolation_key = bone->get_interpolation_key();
 			break;
 		}
@@ -112,5 +112,5 @@
 	for ( size_t i = 0; i < m_node_data->get_count(); ++i )
 	{
-		raw_channel_interpolator interpolator( m_node_data->get_node( i )->data, m_interpolation_key );
+		raw_channel_interpolator interpolator( (*m_node_data)[i], m_interpolation_key );
 		skeleton[i] = interpolator.get< transform >( frame_num );
 	}
@@ -132,8 +132,8 @@
 		for ( uint32 n = 0; n < node_count; ++n )
 		{
-			const mesh_node_data* node = m_node_data->get_node(n);
-			if ( node->data->get_parent_id() != -1 )
-			{
-				m_children[ node->data->get_parent_id()].push_back( 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 );
 			}
 		}
@@ -156,10 +156,10 @@
 		if ( m_bone_ids[n] >= 0 )
 		{
-			const mesh_node_data* node = m_node_data->get_node(n);
-			nv::mat4 node_mat( node->data->get_transform() );
-
-			if ( node->data && node->data->size() > 0 )
-			{
-				raw_channel_interpolator interpolator( node->data, m_interpolation_key );
+			const data_channel_set* node = m_node_data->get_node(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 >( anim_time );
 			}
@@ -177,15 +177,15 @@
 	for ( nv::uint16 bi = 0; bi < bones->get_count(); ++bi )
 	{
-		const mesh_node_data* bone = bones->get_node(bi);
-		bone_names[ bone->data->get_name() ] = bi;
-		m_offsets[bi] = bone->data->get_transform();
+		const data_channel_set* bone = bones->get_node( bi );
+		bone_names[ bone->get_name() ] = bi;
+		m_offsets[bi] = bone->get_transform();
 	}
 
 	for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
 	{
-		const mesh_node_data* node = m_node_data->get_node(n);
+		const data_channel_set* node = m_node_data->get_node( n );
 		sint16 bone_id = -1;
 
-		auto bi = bone_names.find( node->data->get_name() );
+		auto bi = bone_names.find( node->get_name() );
 		if ( bi != bone_names.end() )
 		{
@@ -194,6 +194,6 @@
 		m_bone_ids[n] = bone_id;
 
-		if ( m_interpolation_key.size() == 0 && node->data->size() > 0 )
-			m_interpolation_key = node->data->get_interpolation_key();
+		if ( m_interpolation_key.size() == 0 && node->size() > 0 )
+			m_interpolation_key = node->get_interpolation_key();
 
 	}
@@ -205,10 +205,10 @@
 	// TODO: fix transforms, which are now embedded,
 	//       see note in assimp_loader.cc:load_node
-	const mesh_node_data* node = m_node_data->get_node( node_id );
-	mat4 node_mat( node->data->get_transform() );
-
-	if ( node->data && node->data->size() > 0 )
-	{
-		raw_channel_interpolator interpolator( node->data, m_interpolation_key );
+	const data_channel_set* node = m_node_data->get_node( 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 );
 	}
Index: /trunk/src/io/string_table.cc
===================================================================
--- /trunk/src/io/string_table.cc	(revision 426)
+++ /trunk/src/io/string_table.cc	(revision 427)
@@ -66,5 +66,7 @@
 	m_data.resize( dsize + 2 + length + 1 );
 	*reinterpret_cast<uint16*>( m_data.data() + dsize ) = length;
-	raw_copy( str, str + length + 1, m_data.data() + dsize + 2 );
+	if ( length > 0 )
+		raw_copy( str, str + length, m_data.data() + dsize + 2 );
+	m_data[dsize + 2 + length] = 0;
 	m_map[h] = dsize;
 	return dsize;
