Index: trunk/nv/interface/data_channel.hh
===================================================================
--- trunk/nv/interface/data_channel.hh	(revision 423)
+++ trunk/nv/interface/data_channel.hh	(revision 424)
@@ -83,4 +83,5 @@
 		friend class data_channel_set_creator;
 		friend class raw_data_channel_access;
+		friend class mesh_nodes_creator;
 
 		typedef const raw_data_channel* const_iterator;
@@ -90,5 +91,8 @@
 			for ( uint32 c = 0; c < other.m_size; ++c )
 				m_channels[c] = move( other.m_channels[c] );
-			m_size = other.m_size;
+			m_size      = other.m_size;
+			m_parent_id = other.m_parent_id;
+			m_transform = other.m_transform;
+			m_name      = other.m_name;
 			other.m_size = 0;
 		}
@@ -100,5 +104,8 @@
 				for ( uint32 c = 0; c < other.m_size; ++c )
 					m_channels[c] = move( other.m_channels[c] );
-				m_size = other.m_size;
+				m_size      = other.m_size;
+				m_parent_id = other.m_parent_id;
+				m_transform = other.m_transform;
+				m_name      = other.m_name;
 				other.m_size = 0;
 			}
@@ -201,12 +208,24 @@
 		const_iterator begin() const { return &m_channels[0]; }
 		const_iterator end()   const { return &m_channels[ m_size ]; }
+
+		uint64 get_name() const { return m_name; }
+		sint16 get_parent_id() const { return m_parent_id; }
+		const mat4& get_transform() const { return m_transform; }
+
 	protected:
 
 		data_channel_set()
 		{
-			m_size = 0;
-		}
+			m_size      = 0;
+			m_name      = 0;
+			m_parent_id = -1;
+		}
+
 		raw_data_channel m_channels[4];
+
 		uint32 m_size;
+		uint64 m_name;
+		sint16 m_parent_id;
+		mat4   m_transform;
 	};
 
Index: trunk/nv/interface/data_channel_access.hh
===================================================================
--- trunk/nv/interface/data_channel_access.hh	(revision 423)
+++ trunk/nv/interface/data_channel_access.hh	(revision 424)
@@ -101,10 +101,10 @@
 	public:
 
-		static data_channel_set* create( size_t )
+		static data_channel_set* create_set( size_t )
 		{
 			return new data_channel_set;
 		}
 
-		static data_channel_set* create_array( size_t size, size_t )
+		static data_channel_set* create_set_array( size_t size, size_t )
 		{
 			return new data_channel_set[ size ];
@@ -146,4 +146,5 @@
 		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 )
@@ -152,8 +153,19 @@
 				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; }
+
+		void set_name( uint64 name ) {  m_set->m_name = name; }
+		uint64 get_name() const { return m_set->m_name; }
+
+		void set_parent_id( sint16 name ) { m_set->m_parent_id = name; }
+		sint16 get_parent_id() const { return m_set->m_parent_id; }
 	protected:
 		data_channel_set* m_set;
Index: trunk/nv/interface/mesh_data.hh
===================================================================
--- trunk/nv/interface/mesh_data.hh	(revision 423)
+++ trunk/nv/interface/mesh_data.hh	(revision 424)
@@ -22,9 +22,13 @@
 	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
 	{
-		uint64    name;
-		sint16    parent_id;
-		mat4      transform;
 		data_channel_set* data;
 	};
@@ -48,4 +52,10 @@
 		size_t get_count() const { return m_count; }
 
+		bool is_animated( size_t i ) const
+		{
+			if ( i >= m_count ) return false;
+			return ( m_nodes[i].data && m_nodes[i].data->size() > 0 );
+		}
+
 		const mesh_node_data* get_node( size_t i ) const 
 		{
@@ -58,5 +68,6 @@
 			for ( uint32 i = 0; i < m_count; ++i )
 			{
-				if ( m_nodes[ i ].name == h )
+				NV_ASSERT( m_nodes[i].data, "data!" );
+				if ( m_nodes[ i ].data->get_name() == h )
 					return &m_nodes[ i ];
 			}
@@ -68,5 +79,6 @@
 			for ( uint32 i = 0; i < m_count; ++i )
 			{
-				if ( m_nodes[ i ].name == h )
+				NV_ASSERT( m_nodes[i].data, "data!" );
+				if ( m_nodes[ i ].data->get_name() == h )
 					return int( i );
 			}
Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 423)
+++ trunk/src/formats/assimp_loader.cc	(revision 424)
@@ -108,5 +108,5 @@
 {
 	if ( index >= m_mesh_count ) return nullptr;
-	data_channel_set* result = data_channel_set_creator::create( 2 );
+	data_channel_set* result = data_channel_set_creator::create_set( 2 );
 	load_mesh_data( result, index );
 	return result;
@@ -199,10 +199,8 @@
 		aiBone* bone   = mesh->mBones[m];
 		mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix );
-//		bones[m].name = bone->mName.data;
-		bones[m].name = hash_string< uint64 >( bone->mName.data );
-		bones[m].data = nullptr;
-		bones[m].parent_id = -1;
-//		bones[m].target_id = -1;
-		bones[m].transform = offset;
+		bones[m].data = data_channel_set_creator::create_set( 0 );
+		data_channel_set_creator access( bones[m].data );
+		access.set_name( hash_string< uint64 >( bone->mName.data ) );
+		access.set_transform( offset );
 	}
 	return true;
@@ -302,5 +300,5 @@
 
 				mesh_node_data& bone = bones[b];
-				auto iname = names.find( bone.name );
+				auto iname = names.find( bone.data->get_name() );
 				if ( iname == names.end() )
 				{
@@ -308,5 +306,5 @@
 					uint16 index = uint16( final_bones.size() );
 					final_bones.push_back( bone );
-					names[ bone.name] = index;
+					names[ bone.data->get_name() ] = index;
 					translate[b] = index;
 				}
@@ -390,17 +388,18 @@
 	mesh_node_data& a_data = nodes[ this_id ];
 
-//	a_data.name      = name;
-	a_data.name = hash_string< uint64 >( name.c_str() );
-	a_data.parent_id = parent_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 );
+	access.set_name( hash_string< uint64 >( name.c_str() ) );
+	access.set_parent_id( parent_id );
 	// This value is ignored by the create_transformed_keys, but needed by create_direct_keys!
 	// TODO: find a common solution!
 	//       This is bad because create_transformed_keys never uses node-transformations for
 	//       node's without keys
-	a_data.transform = nv::assimp_mat4_cast( node->mTransformation );
-	if (this_id == 0)
-		a_data.transform = mat4();
-	a_data.data = nullptr;
-
-	if (anode) create_keys( &a_data, anode );
+	access.set_transform( nv::assimp_mat4_cast( node->mTransformation ) );
+	if ( this_id == 0 ) access.set_transform( mat4() );
 
 	nv::sint16 next = this_id + 1;
@@ -421,5 +420,5 @@
 	}
 
-	data->data = data_channel_set_creator::create( 2 );
+	data->data = data_channel_set_creator::create_set( 2 );
 	data_channel_set_creator key_set( data->data );
 
@@ -465,5 +464,5 @@
 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
 	bool has_bones = false;
-	data_channel_set* meshes = data_channel_set_creator::create_array( m_mesh_count, 2 );
+	data_channel_set* meshes = data_channel_set_creator::create_set_array( m_mesh_count, 2 );
 	for ( size_t m = 0; m < m_mesh_count; ++m )
 	{
Index: trunk/src/formats/md2_loader.cc
===================================================================
--- trunk/src/formats/md2_loader.cc	(revision 423)
+++ trunk/src/formats/md2_loader.cc	(revision 424)
@@ -313,5 +313,5 @@
 data_channel_set* nv::md2_loader::release_mesh_data( size_t )
 {
-	data_channel_set* data = data_channel_set_creator::create( 3 );
+	data_channel_set* data = data_channel_set_creator::create_set( 3 );
 	release_mesh_frame( data, -1 );
 	return data;
@@ -367,5 +367,5 @@
 mesh_data_pack* nv::md2_loader::release_mesh_data_pack()
 {
-	data_channel_set* data = data_channel_set_creator::create_array( 1, 3 );
+	data_channel_set* data = data_channel_set_creator::create_set_array( 1, 3 );
 	release_mesh_frame( &data[0], -1 );
 	return new mesh_data_pack( 1, data );
Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 423)
+++ trunk/src/formats/md3_loader.cc	(revision 424)
@@ -324,5 +324,5 @@
 data_channel_set* nv::md3_loader::release_mesh_data( nv::size_t index )
 {
-	data_channel_set* data = data_channel_set_creator::create(3);
+	data_channel_set* data = data_channel_set_creator::create_set(3);
 	release_mesh_frame( data, -1, static_cast< sint32 >( index ) );
 	return data;
@@ -424,10 +424,8 @@
 		const md3_tag_t& rtag = md3->tags[i];
 		string_view name( reinterpret_cast< const char* >(rtag.name) );
-
-		nodes[i].transform = mat4();
-		nodes[i].name = hash_string< uint64 >( name.data() );
-		nodes[i].parent_id = -1;
-		nodes[i].data      = data_channel_set_creator::create( 1 );
-		load_tags( data_channel_set_creator( nodes[i].data ).add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
+		nodes[i].data      = data_channel_set_creator::create_set( 1 );
+		data_channel_set_creator access( nodes[i].data );
+		access.set_name( hash_string< uint64 >( name.data() ) );
+		load_tags( access.add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
 	}
 	int name_;
@@ -442,5 +440,5 @@
 	if ( m_merge_all )
 	{
-		data = data_channel_set_creator::create_array(1,3);
+		data = data_channel_set_creator::create_set_array(1,3);
 		release_mesh_frame( &data[0], -1, -1 );
 		data_channel_set_creator( &data[0] ).set_name( reinterpret_cast< char* >( md3->header.name ) );
@@ -449,5 +447,5 @@
 	{
 		count = md3->header.num_surfaces;
-		data = data_channel_set_creator::create_array( count, 3 );
+		data = data_channel_set_creator::create_set_array( count, 3 );
 		for ( int i = 0; i < count; ++i )
 		{
Index: trunk/src/formats/md5_loader.cc
===================================================================
--- trunk/src/formats/md5_loader.cc	(revision 423)
+++ trunk/src/formats/md5_loader.cc	(revision 424)
@@ -118,5 +118,6 @@
 			{
 				std::string name;
-				sstream >> name >> nodes[i].parent_id;
+				sint16 parent_id;
+				sstream >> name >> parent_id;
 				vec3 pos;
 				quat orient;
@@ -128,10 +129,9 @@
 				unit_quat_w( orient );
 				remove_quotes( name );
-//				nodes[i].name = name;
-				nodes[i].name = hash_string< uint64 >( name.c_str() );
-//				nodes[i].target_id       = -1;
-				nodes[i].parent_id       = -1;
-				nodes[i].transform       = transform( pos, orient ).inverse().extract();
-				nodes[i].data            = nullptr;
+				nodes[i].data       = data_channel_set_creator::create_set( 0 );
+				data_channel_set_creator access( nodes[i].data );
+				access.set_parent_id( parent_id );
+				access.set_transform( transform( pos, orient ).inverse().extract() );
+				access.set_name( hash_string< uint64 >( name.c_str() ) );
 				next_line( sstream );
 			}
@@ -141,5 +141,5 @@
 		{
 			assert( m_type == MESH );
-			data_channel_set* mesh = data_channel_set_creator::create( 4 );
+			data_channel_set* mesh = data_channel_set_creator::create_set( 4 );
 			data_channel_set_creator maccess( mesh );
 
@@ -251,11 +251,12 @@
 			{
 				std::string    name;
-				sstream >> name >> nodes[i].parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
+				sint16 parent_id;
+				sstream >> name >> parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
 				remove_quotes( name );
-//				nodes[i].name = name;
-				nodes[i].name = hash_string< uint64 >( name.c_str() );
-				nodes[i].transform = mat4();
-				nodes[i].data = data_channel_set_creator::create( 1 );
-				data_channel_set_creator( nodes[i].data ).add_channel< md5_key_t >( num_frames );
+				nodes[i].data = data_channel_set_creator::create_set( 1 );
+				data_channel_set_creator access( nodes[i].data );
+				access.add_channel< md5_key_t >( num_frames );
+				access.set_name( hash_string< uint64 >( name.c_str() ) );
+				access.set_parent_id( parent_id );
 				next_line( sstream );
 			}
@@ -391,5 +392,5 @@
 				md5_weight& weight           = weights[start_weight + j];
 				const mesh_node_data&  joint = nodes[weight.joint_id];
-				const transform tr = transform( joint.transform ).inverse();
+				const transform tr = transform( joint.data->get_transform() ).inverse();
 				vec3 rot_pos = tr.get_orientation() * weight.pos;
 
@@ -454,5 +455,5 @@
  		{
 			const mesh_node_data&  joint = nodes[vdata.boneindex[j]];
-			const transform tr = transform( joint.transform ).inverse();
+			const transform tr = transform( joint.data->get_transform() ).inverse();
  			vdata.normal  += ( normal  * tr.get_orientation() ) * vdata.boneweight[j];
  			vdata.tangent += ( tangent * tr.get_orientation() ) * vdata.boneweight[j];
@@ -472,5 +473,5 @@
 		const md5_joint_info& jinfo = joint_infos[i];
 		mesh_node_data& joint = nodes[i];
-		int parent_id         = joint.parent_id;
+		int parent_id         = joint.data->get_parent_id();
 
 		vec3 pos    = base_frames[i].get_position();
@@ -519,5 +520,5 @@
 {
 	uint32 size = m_meshes.size();
-	data_channel_set* meshes = data_channel_set_creator::create_array( size, 4 );
+	data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 4 );
 	for ( uint32 i = 0; i < size; ++i )
 	{
Index: trunk/src/formats/nmd_loader.cc
===================================================================
--- trunk/src/formats/nmd_loader.cc	(revision 423)
+++ trunk/src/formats/nmd_loader.cc	(revision 424)
@@ -37,5 +37,5 @@
 bool nv::nmd_loader::load_mesh( stream& source, const nmd_element_header& e )
 {
-	data_channel_set* mesh = data_channel_set_creator::create( e.children );
+	data_channel_set* mesh = data_channel_set_creator::create_set( e.children );
 	load_channel_set( source, mesh, e );
 //	m_mesh_names.push_back( e.name );
@@ -55,5 +55,5 @@
 {
 	uint32 size = m_meshes.size();
-	data_channel_set* meshes = data_channel_set_creator::create_array( size, 0 );
+	data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 0 );
 	for ( uint32 i = 0; i < size; ++i )
 	{
@@ -119,13 +119,13 @@
 bool nv::nmd_loader::load_node( stream& source, mesh_node_data* data, const nmd_element_header& e )
 {
-	data->name = e.name;
-	data->parent_id = e.parent_id;
-	data->transform = e.transform;
-	data->data = nullptr;
+	data->data = data_channel_set_creator::create_set( e.children );
 	if ( e.children > 0 )
 	{
-		data->data = data_channel_set_creator::create( e.children );
 		load_channel_set( source, data->data, e );
 	}
+	data_channel_set_creator access( data->data );
+	access.set_name( e.name );
+	access.set_parent_id( e.parent_id );
+	access.set_transform( e.transform );
 	return true;
 }
@@ -206,10 +206,10 @@
 	eheader.children   = static_cast<uint16>( chan_count );
 	eheader.size       = chan_size;
-	eheader.name       = node->name;
-	eheader.parent_id  = node->parent_id;
-	eheader.transform  = node->transform;
+	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 ( node->data ) nmd_dump_channel_set( node->data, stream_out );
+	if ( chan_count > 0 ) nmd_dump_channel_set( node->data, stream_out );
 }
 
@@ -238,11 +238,7 @@
 	eheader.children   = static_cast<uint16>( mesh.size() );
 	eheader.size       = size;
-	int uncomment;
-// 	eheader.name       = mesh.get_name();
-// 	eheader.transform  = mesh.get_transform();
-// 	eheader.parent_id  = mesh.get_parent_id();
- 	eheader.name       = 0;
- 	eheader.transform  = mat4();
- 	eheader.parent_id  = -1;
+	eheader.name       = mesh.get_name();
+	eheader.transform  = mesh.get_transform();
+	eheader.parent_id  = mesh.get_parent_id();
 	eheader.attributes = 0;
 	stream_out.write( &eheader, sizeof( eheader ), 1 );
Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 423)
+++ trunk/src/formats/obj_loader.cc	(revision 424)
@@ -326,5 +326,5 @@
 		}
 	
-		data_channel_set* result = data_channel_set_creator::create( 1 );
+		data_channel_set* result = data_channel_set_creator::create_set( 1 );
 		data_channel_set_creator raccess( result );// ( reader->name );
 		uint8* rdata = raccess.add_channel( m_descriptor, reader->size * 3 ).raw_data();
@@ -359,5 +359,5 @@
 {
 	uint32 size = m_meshes.size();
-	data_channel_set* meshes = data_channel_set_creator::create_array( size, 1 );
+	data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 1 );
 	for ( uint32 i = 0; i < size; ++i )
 	{
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 423)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 424)
@@ -56,5 +56,5 @@
 	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, "TAG FAIL" );
+	NV_ASSERT( data && data->size() > 0, "TAG FAIL" );
 	raw_channel_interpolator interpolator( data, 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 423)
+++ trunk/src/gfx/mesh_creator.cc	(revision 424)
@@ -18,5 +18,5 @@
 	for ( size_t i = 0; i < m_data->get_count(); ++i )
 	{
-		sint16 parent_id = m_data->m_nodes[i].parent_id;
+		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 );
@@ -65,6 +65,9 @@
 			}
 
-			data_channel_set* new_keys = data_channel_set_creator::create( 1 );
+			data_channel_set* new_keys = data_channel_set_creator::create_set( 1 );
 			data_channel_set_creator nk_access( new_keys );
+			nk_access.set_name( old_keys->get_name() );
+			nk_access.set_parent_id( old_keys->get_parent_id() );
+			nk_access.set_transform( old_keys->get_transform() );
 			data_channel_access< nv_key_transform > kt_channel( nk_access.add_channel<nv_key_transform>( max_keys ) );
 
@@ -100,5 +103,5 @@
 	{
 		mesh_node_data& node = m_data->m_nodes[i];
-		node.transform = pre_transform * node.transform * post_transform;
+		node.data->m_transform = pre_transform * node.data->m_transform * post_transform;
 		if ( node.data )
 		{
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 423)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 424)
@@ -23,5 +23,5 @@
 	for ( uint32 i = 0; i < bones->get_count(); ++i )
 	{
-		m_bone_offset[i] = transform( bones->get_node(i)->transform );
+		m_bone_offset[i] = transform( bones->get_node(i)->data->get_transform() );
 	}
 
@@ -95,5 +95,5 @@
 	for ( size_t i = 0; i < m_node_data->get_count(); ++i )
 	{
-		if ( m_node_data->get_node( i )->data )
+		if ( m_node_data->is_animated( i ) )
 		{
 			m_interpolation_key = m_node_data->get_node( i )->data->get_interpolation_key();
@@ -133,7 +133,7 @@
 		{
 			const mesh_node_data* node = m_node_data->get_node(n);
-			if ( node->parent_id != -1 )
-			{
-				m_children[ node->parent_id ].push_back( n );
+			if ( node->data->get_parent_id() != -1 )
+			{
+				m_children[ node->data->get_parent_id()].push_back( n );
 			}
 		}
@@ -157,7 +157,7 @@
 		{
 			const mesh_node_data* node = m_node_data->get_node(n);
-			nv::mat4 node_mat( node->transform );
-
-			if ( node->data )
+			nv::mat4 node_mat( node->data->get_transform() );
+
+			if ( node->data && node->data->size() > 0 )
 			{
 				raw_channel_interpolator interpolator( node->data, m_interpolation_key );
@@ -178,6 +178,6 @@
 	{
 		const mesh_node_data* bone = bones->get_node(bi);
-		bone_names[ bone->name ] = bi;
-		m_offsets[bi] = bone->transform;
+		bone_names[ bone->data->get_name() ] = bi;
+		m_offsets[bi] = bone->data->get_transform();
 	}
 
@@ -187,5 +187,5 @@
 		sint16 bone_id = -1;
 
-		auto bi = bone_names.find( node->name );
+		auto bi = bone_names.find( node->data->get_name() );
 		if ( bi != bone_names.end() )
 		{
@@ -194,5 +194,5 @@
 		m_bone_ids[n] = bone_id;
 
-		if ( m_interpolation_key.size() == 0 && node->data )
+		if ( m_interpolation_key.size() == 0 && node->data->size() > 0 )
 			m_interpolation_key = node->data->get_interpolation_key();
 
@@ -206,7 +206,7 @@
 	//       see note in assimp_loader.cc:load_node
 	const mesh_node_data* node = m_node_data->get_node( node_id );
-	mat4 node_mat( node->transform );
-
-	if ( node->data )
+	mat4 node_mat( node->data->get_transform() );
+
+	if ( node->data && node->data->size() > 0 )
 	{
 		raw_channel_interpolator interpolator( node->data, m_interpolation_key );
