Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 419)
+++ trunk/src/formats/assimp_loader.cc	(revision 420)
@@ -199,8 +199,9 @@
 		aiBone* bone   = mesh->mBones[m];
 		mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix );
-		bones[m].name = bone->mName.data;
+//		bones[m].name = bone->mName.data;
+		bones[m].name_hash = hash_string< uint64 >( bone->mName.data );
 		bones[m].data = nullptr;
 		bones[m].parent_id = -1;
-		bones[m].target_id = -1;
+//		bones[m].target_id = -1;
 		bones[m].transform = offset;
 	}
@@ -287,5 +288,5 @@
 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
 	vector< mesh_node_data > final_bones;
-	unordered_map< std::string, uint16 > names;
+	unordered_map< uint64, uint16 > names;
 	for ( unsigned int m = 0; m < m_mesh_count; ++m )
 	{
@@ -301,5 +302,5 @@
 
 				mesh_node_data& bone = bones[b];
-				auto iname = names.find( bone.name );
+				auto iname = names.find( bone.name_hash );
 				if ( iname == names.end() )
 				{
@@ -307,5 +308,5 @@
 					uint16 index = uint16( final_bones.size() );
 					final_bones.push_back( bone );
-					names[ bone.name ] = index;
+					names[ bone.name_hash] = index;
 					translate[b] = index;
 				}
@@ -387,6 +388,6 @@
 	mesh_node_data& a_data = nodes[ this_id ];
 
-	a_data.name      = name;
-	a_data.target_id = -1;
+//	a_data.name      = name;
+	a_data.name_hash = hash_string< uint64 >( name.c_str() );
 	a_data.parent_id = parent_id;
 	// This value is ignored by the create_transformed_keys, but needed by create_direct_keys!
Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 419)
+++ trunk/src/formats/md3_loader.cc	(revision 420)
@@ -426,7 +426,6 @@
 
 		nodes[i].transform = mat4();
-		nodes[i].name      = name.to_string();
+		nodes[i].name_hash = hash_string< uint64 >( name.data() );
 		nodes[i].parent_id = -1;
-		nodes[i].target_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 );
Index: trunk/src/formats/md5_loader.cc
===================================================================
--- trunk/src/formats/md5_loader.cc	(revision 419)
+++ trunk/src/formats/md5_loader.cc	(revision 420)
@@ -116,5 +116,6 @@
 			for ( size_t i = 0; i < m_nodes->get_count(); ++i )
 			{
-				sstream >> nodes[i].name >> nodes[i].parent_id;
+				std::string name;
+				sstream >> name >> nodes[i].parent_id;
 				vec3 pos;
 				quat orient;
@@ -125,6 +126,8 @@
 				sstream >> orient.x >> orient.y >> orient.z;
 				unit_quat_w( orient );
-				remove_quotes( nodes[i].name );
-				nodes[i].target_id       = -1;
+				remove_quotes( name );
+//				nodes[i].name = name;
+				nodes[i].name_hash = hash_string< uint64 >( name.c_str() );
+//				nodes[i].target_id       = -1;
 				nodes[i].parent_id       = -1;
 				nodes[i].transform       = transform( pos, orient ).inverse().extract();
@@ -246,8 +249,9 @@
 			{
 				std::string    name;
-				sstream >> nodes[i].name >> nodes[i].parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
+				sstream >> name >> nodes[i].parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
 				remove_quotes( name );
+//				nodes[i].name = name;
+				nodes[i].name_hash = hash_string< uint64 >( name.c_str() );
 				nodes[i].transform = mat4();
-				nodes[i].target_id = -1;
 				nodes[i].data = data_channel_set_creator::create( 1 );
 				data_channel_set_creator( nodes[i].data ).add_channel< md5_key_t >( num_frames );
Index: trunk/src/formats/nmd_loader.cc
===================================================================
--- trunk/src/formats/nmd_loader.cc	(revision 419)
+++ trunk/src/formats/nmd_loader.cc	(revision 420)
@@ -18,13 +18,15 @@
 	nmd_header root_header;
 	source.read( &root_header, sizeof( root_header ), 1 );
+	skip_attributes( source, root_header.attributes );
 	for ( uint32 i = 0; i < root_header.elements; ++i )
 	{
 		nmd_element_header element_header;
 		source.read( &element_header, sizeof( element_header ), 1 );
+		skip_attributes( source, element_header.attributes );
 		switch ( element_header.type )
 		{
 		case nmd_type::MESH           : load_mesh( source, element_header ); break;
 		case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
-		case nmd_type::STRING_TABLE   : load_strings( source ); break;
+//		case nmd_type::STRING_TABLE   : load_strings( source ); break;
 		default: NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); break;
 		}
@@ -36,17 +38,6 @@
 {
 	data_channel_set* mesh = data_channel_set_creator::create( e.children );
-	data_channel_set_creator mcreator( mesh );
-	for ( uint32 s = 0; s < e.children; ++s )
-	{
-		nmd_element_header element_header;
-		source.read( &element_header, sizeof( element_header ), 1 );
-		NV_ASSERT( element_header.type == nmd_type::STREAM, "STREAM expected!" );
-
-		nmd_stream_header stream_header;
-		source.read( &stream_header, sizeof( stream_header ), 1 );
-		raw_data_channel_access channel( mcreator.add_channel( stream_header.format, stream_header.count ) );
-		source.read( channel.raw_data(), channel.element_size(), channel.size() );
-	}
-	m_mesh_names.push_back( e.name );
+	load_channel_set( source, mesh, e );
+//	m_mesh_names.push_back( e.name );
 	m_meshes.push_back( mesh );
 	return true;
@@ -56,5 +47,5 @@
 {
 	data_channel_set* result = m_meshes[ index ];
-	if ( m_strings ) data_channel_set_creator( result ).set_name( m_strings->get( m_mesh_names[ index ] ) );
+//	if ( m_strings ) data_channel_set_creator( result ).set_name( m_strings->get( m_mesh_names[ index ] ) );
 	m_meshes[ index ] = nullptr;
 	return result;
@@ -77,13 +68,19 @@
 {
 	for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
-	if ( m_strings )   delete m_strings;
+//	if ( m_strings )   delete m_strings;
 	if ( m_node_data ) delete m_node_data;
 	m_meshes.clear();
-	m_mesh_names.clear();
-	m_node_names.clear();
+//	m_mesh_names.clear();
+//	m_node_names.clear();
 
 	m_node_data  = nullptr;
 	m_node_array = nullptr;
-	m_strings    = nullptr;
+//	m_strings    = nullptr;
+}
+
+void nv::nmd_loader::skip_attributes( stream& source, uint32 count )
+{
+	if ( count == 0 ) return;
+	source.seek( count * sizeof( nmd_attribute ), origin::CUR );
 }
 
@@ -93,8 +90,8 @@
 }
 
-bool nv::nmd_loader::load_strings( stream& source )
-{
-	NV_ASSERT( m_strings == nullptr, "MULTIPLE STRING ENTRIES!" );
-	m_strings = new string_table( &source );
+bool nv::nmd_loader::load_strings( stream& /*source*/ )
+{
+//	NV_ASSERT( m_strings == nullptr, "MULTIPLE STRING ENTRIES!" );
+//	m_strings = new string_table( &source );
 	return true;
 }
@@ -110,28 +107,8 @@
 		nmd_element_header element_header;
 		source.read( &element_header, sizeof( element_header ), 1 );
+		skip_attributes( source, element_header.attributes );
 		NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
-		m_node_names.push_back( element_header.name );
-		uint16 ch_count = element_header.children;
-
-		nmd_node_header node_header;
-		source.read( &node_header, sizeof( node_header ), 1 );
-		m_node_array[i].parent_id     = node_header.parent_id;
-		m_node_array[i].transform     = node_header.transform;
-		m_node_array[i].data          = nullptr;
-		if ( ch_count > 0 )
-		{
-			data_channel_set* kdata = data_channel_set_creator::create( ch_count );
-			data_channel_set_creator kaccess( kdata );
-			m_node_array[i].data = kdata;
-			for ( uint32 c = 0; c < ch_count; ++c )
-			{
-				source.read( &element_header, sizeof( element_header ), 1 );
-				NV_ASSERT( element_header.type == nmd_type::KEY_CHANNEL, "CHANNEL expected!" );
-				nv::nmd_stream_header cheader;
-				source.read( &cheader, sizeof( cheader ), 1 );
-				raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) );
-				source.read( channel.raw_data(), channel.element_size(), channel.size() );
-			}
-		}
+//		m_node_names.push_back( element_header.name );
+		load_node( source, &m_node_array[i], element_header );
 	}
 	m_node_data = new mesh_nodes_data( "animation", e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
@@ -139,15 +116,50 @@
 }
 
+bool nv::nmd_loader::load_node( stream& source, mesh_node_data* data, const nmd_element_header& e )
+{
+	data->name_hash = e.name_hash;
+	data->parent_id = e.parent_id;
+	data->transform = e.transform;
+	data->data = nullptr;
+	if ( e.children > 0 )
+	{
+		data->data = data_channel_set_creator::create( e.children );
+		load_channel_set( source, data->data, e );
+	}
+	return true;
+}
+
+bool nv::nmd_loader::load_channel( stream& source, data_channel_set* channel_set )
+{
+	data_channel_set_creator kaccess( channel_set );
+	nmd_channel_header cheader;
+	source.read( &cheader, sizeof( cheader ), 1 );
+	raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) );
+	source.read( channel.raw_data(), channel.element_size(), channel.size() );
+	return true;
+}
+
+bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, const nmd_element_header& e )
+{
+	data_channel_set_creator kaccess( channel_set );
+	for ( uint32 c = 0; c < e.children; ++c )
+	{
+		load_channel( source, channel_set );
+	}
+	return true;
+}
+
 mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
 {
 	if ( m_node_data )
 	{
-		if ( m_strings )
-		{
-			for ( uint32 i = 0; i < m_node_data->get_count(); ++i )
-			{
-				m_node_array[i].name = m_strings->get( m_node_names[i] );
-			}
-		}
+// 		if ( m_strings )
+// 		{
+// 			for ( uint32 i = 0; i < m_node_data->get_count(); ++i )
+// 			{
+// 				m_node_array[i].name = m_strings->get( m_node_names[i] );
+// 				m_node_array[i].name_hash = hash_string< uint64 >( m_strings->get( m_node_names[i] ) );
+// 			}
+// 		}
 		mesh_nodes_data* result = m_node_data;
 		m_node_data = nullptr;
@@ -161,38 +173,67 @@
 // 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_mesh( const data_channel_set* mesh, stream& stream_out )
 {
-	uint32 size = sizeof( nmd_element_header );
+	uint32 size = 0;
 	for ( auto& chan : *mesh )
 	{
-		size += sizeof( nmd_element_header ) + sizeof( nmd_stream_header );
+		size += sizeof( nmd_channel_header );
 		size += chan.raw_size();
 	}
 
 	nmd_element_header eheader;
-	eheader.type     = nmd_type::MESH;
-	eheader.name     = 0;
-	eheader.children = static_cast< uint16 >( mesh->size() );
-	eheader.size     = size;
+	eheader.type       = nmd_type::MESH;
+//	eheader.name       = 0;
+	eheader.children   = static_cast< uint16 >( mesh->size() );
+	eheader.size       = size;
+	eheader.name_hash  = 0;
+	eheader.transform  = mat4();
+	eheader.parent_id  = -1;
+	eheader.attributes = 0;
 	stream_out.write( &eheader, sizeof( eheader ), 1 );
-
-	for ( auto& chan : *mesh )
-	{
-		nmd_element_header cheader;
-		eheader.name     = 0;
-		cheader.type     = nmd_type::STREAM;
-		cheader.children = 0;
-		cheader.size     = chan.raw_size() + sizeof( nmd_stream_header );
-		stream_out.write( &cheader, sizeof( cheader ), 1 );
-
-		nmd_stream_header sheader;
-		sheader.format = chan.descriptor();
-		sheader.count  = chan.size();
-		stream_out.write( &sheader, sizeof( sheader ), 1 );
-		stream_out.write( chan.raw_data(), chan.element_size(), chan.size() );
-	}
-}
-
-static void nmd_dump_nodes_data( const mesh_nodes_data* nodes, stream& stream_out, string_table_creator* strings )
+	nmd_dump_channel_set( mesh, 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.name     = strings->insert( node->name );
+	eheader.children   = static_cast<uint16>( chan_count );
+	eheader.size       = chan_size;
+	eheader.name_hash  = node->name_hash;
+	eheader.parent_id  = node->parent_id;
+	eheader.transform  = node->transform;
+	eheader.attributes = 0;
+	stream_out.write( &eheader, sizeof( eheader ), 1 );
+	if ( node->data ) nmd_dump_channel_set( node->data, stream_out );
+}
+
+static void nmd_dump_nodes_data( const mesh_nodes_data* nodes, stream& stream_out, string_table_creator* /*strings*/ )
 {
 	uint32 total = sizeof( nmd_animation_header );
@@ -200,9 +241,9 @@
 	{
 		const mesh_node_data* node = nodes->get_node(i);
-		total += sizeof( nmd_element_header ) + sizeof( nmd_node_header );
+		total += sizeof( nmd_element_header );
 		if ( node->data )
 			for ( uint32 c = 0; c < node->data->size(); ++c )
 			{
-				total += sizeof( nmd_element_header ) + sizeof( nmd_stream_header );
+				total += sizeof( nmd_channel_header );
 				total += node->data->get_channel(c)->raw_size();
 			}
@@ -210,8 +251,13 @@
 
 	nmd_element_header header;
-	header.name     = 0;
-	header.type     = nmd_type::ANIMATION;
-	header.children = static_cast< uint16 >( nodes->get_count() );
-	header.size     = total;
+//	header.name       = 0;
+	header.type       = nmd_type::ANIMATION;
+	header.children   = static_cast< uint16 >( nodes->get_count() );
+	header.size       = total;
+	header.name_hash  = 0;
+	header.transform  = mat4();
+	header.parent_id  = -1;
+	header.attributes = 0;
+
 	stream_out.write( &header, sizeof( header ), 1 );
 
@@ -224,40 +270,5 @@
 	for ( uint32 i = 0; i < nodes->get_count(); ++i )
 	{
-		const mesh_node_data* node = nodes->get_node(i);
-		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_element_header ) + sizeof( nv::nmd_stream_header );
-			chan_size += node->data->get_channel(c)->raw_size();
-		}
-
-		nmd_element_header eheader;
-		eheader.type     = nmd_type::NODE;
-		eheader.name     = strings->insert( node->name );
-		eheader.children = static_cast< uint16 >( chan_count );
-		eheader.size     = sizeof( nmd_node_header ) + chan_size;
-		stream_out.write( &eheader, sizeof( eheader ), 1 );
-
-		nmd_node_header nheader;
-		nheader.parent_id = node->parent_id;
-		nheader.transform = node->transform;
-		stream_out.write( &nheader, sizeof( nheader ), 1 );
-
-		for ( uint32 c = 0; c < chan_count; ++c )
-		{
-			const raw_data_channel* channel = node->data->get_channel(c);
-
-			eheader.type     = nmd_type::KEY_CHANNEL;
-			eheader.children = 0;
-			eheader.size     = sizeof( nmd_stream_header ) + channel->raw_size();
-			stream_out.write( &eheader, sizeof( eheader ), 1 );
-
-			nmd_stream_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() );
-		}
+		nmd_dump_node( nodes->get_node( i ), stream_out );
 	}
 }
@@ -269,9 +280,10 @@
 		nmd_header header;
 		header.id       = four_cc<'n','m','f','1'>::value;
-		header.elements = 1; // +1 string array
+		header.elements = 0; // +1 string array
 		header.elements += model->get_count();
 		if ( model->get_nodes() && model->get_nodes()->get_count() > 0 ) 
 			header.elements += 1;//  +1 bone array
 		header.version  = 1;
+		header.attributes = 0;
 		stream_out.write( &header, sizeof( header ), 1 );
 	}
@@ -288,10 +300,11 @@
 	}
 
-	nmd_element_header sheader;
-	sheader.type     = nv::nmd_type::STRING_TABLE;
-	sheader.name     = 0;
-	sheader.size     = strings.dump_size();
-	sheader.children = 0;
-	stream_out.write( &sheader, sizeof( sheader ), 1 );
-	strings.dump( &stream_out );
-}
+// 	nmd_element_header sheader;
+// 	sheader.type     = nv::nmd_type::STRING_TABLE;
+// 	sheader.name     = 0;
+// 	sheader.size     = strings.dump_size();
+// 	sheader.children = 0;
+//  sheader.attributes = 0;
+// 	stream_out.write( &sheader, sizeof( sheader ), 1 );
+// 	strings.dump( &stream_out );
+}
