Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 480)
+++ trunk/src/formats/assimp_loader.cc	(revision 482)
@@ -105,12 +105,12 @@
 }
 
-data_channel_set* nv::assimp_loader::release_mesh_data( size_t index /*= 0 */ )
+data_channel_set* nv::assimp_loader::release_mesh_data( size_t index, data_node_info& info )
 {
 	if ( index >= m_mesh_count ) return nullptr;
 	data_channel_set* result = data_channel_set_creator::create_set( 2 );
-	load_mesh_data( result, index );
+	load_mesh_data( result, index, info );
 	return result;
 }
-void nv::assimp_loader::load_mesh_data( data_channel_set* data, size_t index )
+void nv::assimp_loader::load_mesh_data( data_channel_set* data, size_t index, data_node_info& info )
 {
 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
@@ -126,5 +126,6 @@
 	data_channel_set_creator maccess( data );
 	const char* name = mesh->mName.data;
-	maccess.set_name( make_name( name ) );
+	info.name = make_name( name );
+	info.parent_id = -1;
 	uint8*  cdata   = maccess.add_channel( desc, mesh->mNumVertices ).raw_data();
 	uint16* indices = reinterpret_cast<uint16*>( maccess.add_channel< index_u16 >( mesh->mNumFaces * 3 ).raw_data() );
@@ -190,5 +191,5 @@
 }
 
-bool nv::assimp_loader::load_bones( size_t index, array_ref< data_channel_set* > bones )
+bool nv::assimp_loader::load_bones( size_t index, array_ref< data_node_info > bones )
 {
 	if ( m_scene == nullptr ) return false;
@@ -200,9 +201,7 @@
 		aiBone* bone   = mesh->mBones[m];
 		mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix );
-		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 ) );
-		access.set_transform( offset );
+		bones[m].name = make_name( name );
+		bones[m].transform = offset;
 	}
 	return true;
@@ -284,23 +283,24 @@
 }
 
-mesh_nodes_data* nv::assimp_loader::release_merged_bones( data_channel_set* meshes )
-{
-	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
-	mesh_nodes_data* result = new mesh_nodes_data( make_name( "bones" ) );
+data_node_list* nv::assimp_loader::release_merged_bones( data_channel_set* meshes )
+{
+	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
+	data_node_list* result = new data_node_list( make_name( "bones" ) );
 	hash_store< shash64, uint16 > names;
 	for ( unsigned int m = 0; m < m_mesh_count; ++m )
 	{
 		uint16 translate[MAX_BONES];
-		vector< data_channel_set* > bones;
+		vector< data_node_info > bones;
 		const aiMesh*  mesh  = scene->mMeshes[ m ];
 		if ( mesh->mNumBones != 0 )
 		{
 			bones.resize( mesh->mNumBones );
+			NV_ASSERT( false, "parent ids for bones are not loaded!" );
 			load_bones( m, bones );
 			for ( unsigned int b = 0; b < mesh->mNumBones; ++b )
 			{
 
-				data_channel_set* bone = bones[b];
-				auto iname = names.find( bone->get_name() );
+				data_node_info bone = bones[b];
+				auto iname = names.find( bone.name );
 				if ( iname == names.end() )
 				{
@@ -308,5 +308,5 @@
 					uint16 index = uint16( result->size() );
 					result->append( bone );
-					names[ bone->get_name() ] = index;
+					names[ bone.name ] = index;
 					translate[b] = index;
 				}
@@ -334,5 +334,5 @@
 		}	
 	}
-	result->initialize();
+	//result->initialize();
 
 	return result;
@@ -352,18 +352,39 @@
 	uint16 frame_rate     = static_cast<uint16>( anim->mTicksPerSecond );
 	uint16 duration       = static_cast<uint16>( anim->mDuration );
-	bool   flat           = false;
-
-	data_channel_set** temp = new data_channel_set*[ count ];
+
+	data_channel_set** temp  = new data_channel_set*[ count ];
+	data_node_info*    temp2 = new data_node_info[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->append( set );
+	array_ref< data_node_info >    temp2_ref( temp2, count );
+	load_node( index, temp_ref, temp2_ref, root, 0, -1 );
+
+	mesh_nodes_data* result = new mesh_nodes_data( make_name( static_cast<const char*>( anim->mName.data ) ), frame_rate, duration );
+	for ( nv::uint32 i = 0; i < count; ++i )
+	{
+		result->append( temp_ref[i], temp2_ref[i] );
 	}
 	result->initialize();
 	delete temp;
+	delete temp2;
 	return result;
+}
+
+data_node_list* nv::assimp_loader::release_data_node_list( size_t index /*= 0 */ )
+{
+	int this_is_incorrect;
+	NV_ASSERT( false, "unimplemented!" );
+// 	mesh_nodes_data* half_result = release_mesh_nodes_data( index );
+// 	data_node_list* result = new data_node_list( half_result->get_name() );
+// 	for ( auto node : *half_result )
+// 		result->append( node->get_info() );
+// 	delete half_result;
+//	return result;
+	return nullptr;
+}
+
+bool nv::assimp_loader::is_animated( size_t /*= 0 */ )
+{
+	int this_is_incorrect;
+	return false;
 }
 
@@ -379,5 +400,5 @@
 }
 
-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 )
+nv::sint16 nv::assimp_loader::load_node( uint32 anim_id, array_ref< data_channel_set* > nodes, array_ref< data_node_info > infos, const void* vnode, sint16 this_id, sint16 parent_id )
 {
 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
@@ -396,18 +417,18 @@
 	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 );
+	infos[this_id].name      = make_name( name );
+	infos[this_id].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
-	access.set_transform( nv::assimp_mat4_cast( node->mTransformation ) );
-	if ( this_id == 0 ) access.set_transform( mat4() );
+	// TODO: this can probably be deleted
+	infos[this_id].transform = nv::assimp_mat4_cast( node->mTransformation );
+	if ( this_id == 0 ) infos[this_id].transform = mat4();
 
 	nv::sint16 next = this_id + 1;
 	for ( unsigned i = 0; i < node->mNumChildren; ++i )
 	{
-		next = load_node( anim_id, nodes, node->mChildren[i], next, this_id );
+		next = load_node( anim_id, nodes, infos, node->mChildren[i], next, this_id );
 	}
 
Index: trunk/src/formats/nmd_loader.cc
===================================================================
--- trunk/src/formats/nmd_loader.cc	(revision 480)
+++ trunk/src/formats/nmd_loader.cc	(revision 482)
@@ -37,13 +37,16 @@
 {
 	data_channel_set* mesh = data_channel_set_creator::create_set( e.children );
-	load_channel_set( source, mesh, e );
+	data_node_info info;
+	load_channel_set( source, mesh, info, e );
 //	m_mesh_names.push_back( e.name );
+	m_infos.push_back( info );
 	m_meshes.push_back( mesh );
 	return true;
 }
 
-data_channel_set* nv::nmd_loader::release_mesh_data( size_t index )
+data_channel_set* nv::nmd_loader::release_mesh_data( size_t index, data_node_info& info )
 {
 	data_channel_set* result = m_meshes[ index ];
+	info = m_infos[ index ];
 	m_meshes[ index ] = nullptr;
 	return result;
@@ -54,7 +57,9 @@
 	for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
 	if ( m_node_data ) delete m_node_data;
+	if ( m_bone_data ) delete m_bone_data;
 	m_meshes.clear();
 
-	m_node_data  = nullptr;
+	m_node_data = nullptr;
+	m_bone_data = nullptr;
 }
 
@@ -85,5 +90,6 @@
 	nmd_animation_header animation_header;
 	source.read( &animation_header, sizeof( animation_header ), 1 );
-	m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.frame_count, animation_header.flat );
+	m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.frame_count );
+	m_bone_data = new data_node_list( e.name );
 	for ( uint32 i = 0; i < e.children; ++i )
 	{
@@ -93,6 +99,8 @@
 		NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
 		data_channel_set* set = data_channel_set_creator::create_set( element_header.children );
-		load_channel_set( source, set, element_header );
-		m_node_data->append( set );
+		data_node_info info;
+		load_channel_set( source, set, info, element_header );
+		m_bone_data->append( info );
+		m_node_data->append( set, info );
 	}
 	m_node_data->initialize();
@@ -110,5 +118,5 @@
 }
 
-bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, const nmd_element_header& e )
+bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, data_node_info& info, const nmd_element_header& e )
 {
 	data_channel_set_creator kaccess( channel_set );
@@ -117,8 +125,7 @@
 		load_channel( source, channel_set );
 	}
-	data_channel_set_creator access( channel_set );
-	access.set_name( e.name );
-	access.set_parent_id( e.parent_id );
-	access.set_transform( e.transform );
+	info.name = e.name;
+	info.parent_id = e.parent_id;
+	info.transform = e.transform;
 	return true;
 }
@@ -126,11 +133,20 @@
 mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
 {
-	if ( m_node_data )
-	{
-		mesh_nodes_data* result = m_node_data;
-		m_node_data = nullptr;
-		return result;
-	}
-	return nullptr;
+	mesh_nodes_data* result = m_node_data;
+	m_node_data = nullptr;
+	return result;
+}
+
+data_node_list* nv::nmd_loader::release_data_node_list( size_t )
+{
+	data_node_list* result = m_bone_data;
+	m_bone_data = nullptr;
+	return result;
+}
+
+bool nv::nmd_loader::is_animated( size_t /*= 0 */ )
+{
+	if ( !m_node_data ) return false;
+	return m_node_data->is_animated();
 }
 
@@ -150,5 +166,5 @@
 }
 
-void nv::nmd_dump_element( stream& stream_out, const data_channel_set& data, nmd_type type )
+void nv::nmd_dump_element( stream& stream_out, const data_channel_set& data, const data_node_info& info, nmd_type type )
 {
 	uint32 size = 0;
@@ -163,7 +179,7 @@
 	eheader.children   = static_cast<uint16>( data.size() );
 	eheader.size       = size;
-	eheader.name       = data.get_name();
-	eheader.transform  = data.get_transform();
-	eheader.parent_id  = data.get_parent_id();
+	eheader.name       = info.name;
+	eheader.transform  = info.transform;
+	eheader.parent_id  = info.parent_id;
 	eheader.attributes = 0;
 	stream_out.write( &eheader, sizeof( eheader ), 1 );
@@ -205,10 +221,49 @@
 	aheader.frame_rate  = nodes.get_fps();
 	aheader.frame_count = nodes.get_frame_count();
-	aheader.flat = nodes.is_flat();
+	aheader.unused      = false;
 	stream_out.write( &aheader, sizeof( aheader ), 1 );
 
+	for ( uint32 i = 0; i < nodes.size(); ++i )
+	{
+		nmd_dump_element( stream_out, *nodes[i], nodes.get_info(i), nv::nmd_type::NODE );
+	}
+}
+
+void nv::nmd_dump_bones( stream& stream_out, const data_node_list& nodes )
+{
+	uint32 total = sizeof( nmd_animation_header );
 	for ( auto node : nodes )
 	{
-		nmd_dump_element( stream_out, *node, nv::nmd_type::NODE );
+		total += sizeof( nmd_element_header );
+	}
+
+	nmd_element_header header;
+	header.type = nmd_type::ANIMATION;
+	header.children = static_cast<uint16>( nodes.size() );
+	header.size = total;
+	header.name = nodes.get_name();
+	header.transform = mat4();
+	header.parent_id = -1;
+	header.attributes = 0;
+
+	stream_out.write( &header, sizeof( header ), 1 );
+
+	nmd_animation_header aheader;
+	aheader.frame_rate = 0;
+	aheader.frame_count = 0;
+	aheader.unused = false;
+	stream_out.write( &aheader, sizeof( aheader ), 1 );
+
+	for ( auto node : nodes )
+	{
+		nmd_element_header eheader;
+		eheader.type = nv::nmd_type::NODE;
+		eheader.children = 0;
+		eheader.size = 0;
+		eheader.name = node.name;
+		eheader.transform = node.transform;
+		eheader.parent_id = node.parent_id;
+		eheader.attributes = 0;
+		stream_out.write( &eheader, sizeof( eheader ), 1 );
 	}
 }
@@ -227,5 +282,5 @@
 }
 
-void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, const mesh_nodes_data* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
+void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const mesh_nodes_data* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
 {
 	uint32 elements = ( strings ? 1 : 0 ) // +1 string array
@@ -237,5 +292,5 @@
 	{
 		NV_ASSERT( meshes[i], "mesh is null!" );
-		nmd_dump_element( stream_out, *meshes[i], nv::nmd_type::MESH );
+		nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );
 	}
 
@@ -243,4 +298,28 @@
 	{
 		nmd_dump_nodes( stream_out, *nodes );
+	}
+
+	if ( strings )
+	{
+		nmd_dump_strings( stream_out, *strings );
+	}
+}
+
+void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const nv::data_node_list* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
+{
+	uint32 elements = ( strings ? 1 : 0 ) // +1 string array
+		+ meshes.size() // meshes
+		+ ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes
+	nmd_dump_header( stream_out, elements, name );
+
+	for ( uint32 i = 0; i < meshes.size(); ++i )
+	{
+		NV_ASSERT( meshes[i], "mesh is null!" );
+		nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );
+	}
+
+	if ( nodes && nodes->size() > 0 )
+	{
+		nmd_dump_bones( stream_out, *nodes );
 	}
 
Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 480)
+++ trunk/src/formats/obj_loader.cc	(revision 482)
@@ -327,7 +327,6 @@
 	
 		data_channel_set* result = data_channel_set_creator::create_set( 1 );
-		data_channel_set_creator raccess( result );
-		raccess.set_name( make_name( reader->name ) );
-		uint8* rdata = raccess.add_channel( m_descriptor, reader->size * 3 ).raw_data();
+
+		uint8* rdata = data_channel_set_creator(result).add_channel( m_descriptor, reader->size * 3 ).raw_data();
 
 		if ( reader->raw_size() > 0 )
@@ -335,5 +334,8 @@
 			raw_copy_n( reader->raw_pointer(), reader->raw_size(), rdata );
 		}
-
+		data_node_info info;
+		info.name = make_name( reader->name );
+		info.parent_id = -1;
+		m_infos.push_back( info );
 		m_meshes.push_back( result );
 
@@ -345,7 +347,8 @@
 }
 
-data_channel_set* nv::obj_loader::release_mesh_data( size_t index )
+data_channel_set* nv::obj_loader::release_mesh_data( size_t index, data_node_info& info )
 {
 	data_channel_set* result = m_meshes[ index ];
+	info = m_infos[index];
 	m_meshes[ index ] = nullptr;
 	return result;
