Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 482)
+++ trunk/src/formats/assimp_loader.cc	(revision 485)
@@ -12,4 +12,20 @@
 
 using namespace nv;
+
+namespace nv {
+
+	struct assimp_data
+	{
+		const aiScene* scene;
+		vector< const aiBone* > bones;
+		vector< const aiNode* > nodes;
+		vector< const aiMesh* > meshes;
+		vector< const aiNode* > skeletons;
+
+		hash_store< shash64, const aiBone* > bone_by_name;
+		hash_store< shash64, const aiNode* > node_by_name;
+	};
+
+}
 
 const unsigned MAX_BONES = 64;
@@ -58,5 +74,5 @@
 
 nv::assimp_loader::assimp_loader( string_table* strings, const string_view& a_ext, uint32 a_assimp_flags /*= 0 */ )
-	: mesh_loader( strings ), m_scene( nullptr ), m_mesh_count(0)
+	: mesh_loader( strings ), m_mesh_count(0)
 {
 	m_ext   = a_ext;
@@ -76,7 +92,9 @@
 			aiProcess_SortByPType                   |  
 			aiProcess_FindDegenerates               |  
-			aiProcess_FindInvalidData               |  
+			aiProcess_FindDegenerates |
 			0 );
 	}
+	m_data = new assimp_data;
+	m_data->scene = nullptr;
 }
 
@@ -85,6 +103,6 @@
 {
 	load_assimp_library();
-	if ( m_scene != nullptr ) aiReleaseImport( reinterpret_cast<const aiScene*>( m_scene ) );
-	m_scene = nullptr;
+	if ( m_data->scene != nullptr ) aiReleaseImport( m_data->scene );
+	m_data->scene = nullptr;
 	m_mesh_count = 0;
 	NV_LOG_NOTICE( "AssImp loading file..." );
@@ -99,7 +117,27 @@
 		return false;
 	}
-	m_scene      = scene;
-	m_mesh_count = scene->mNumMeshes;
+	m_data->scene = scene;
+	m_mesh_count  = scene->mNumMeshes;
 	NV_LOG_NOTICE( "Loading successfull" );
+
+	scan_nodes( scene->mRootNode );
+
+	for ( unsigned i = 0; i < scene->mRootNode->mNumChildren; ++i )
+	{
+		const aiNode* node = scene->mRootNode->mChildren[i];
+		if ( node->mNumMeshes == 0 )
+			m_data->skeletons.push_back( node );
+	}
+
+	for ( nv::uint32 i = 0; i < m_mesh_count; i++ )
+	{
+ 		data_node_info info;
+		data_channel_set* data = data_channel_set_creator::create_set( 2 );
+		load_mesh_data( data, i, info );
+		m_meshes.push_back( data );
+		m_mesh_info.push_back( info );
+	}
+
+	scene_report();
 	return true;
 }
@@ -108,12 +146,10 @@
 {
 	if ( index >= m_mesh_count ) return nullptr;
-	data_channel_set* result = data_channel_set_creator::create_set( 2 );
-	load_mesh_data( result, index, info );
-	return result;
+	info = m_mesh_info[index];
+	return m_meshes[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 );
-	const aiMesh*  mesh  = scene->mMeshes[ index ];
+	const aiMesh*  mesh  = m_data->scene->mMeshes[ index ];
 
 	bool skinned = mesh->mNumBones > 0;
@@ -125,7 +161,30 @@
 		desc.initialize< assimp_plain_vtx >();
 	data_channel_set_creator maccess( data );
-	const char* name = mesh->mName.data;
+	string64 name( mesh->mName.data, mesh->mName.length );
+	if ( mesh->mName.length == 0 )
+	{
+		for ( auto node : m_data->nodes )
+		{
+			if ( node->mMeshes )
+				for ( uint32 i = 0; i < node->mNumMeshes; ++i )
+					if ( node->mMeshes[i] == index )
+					{
+						name.assign( node->mName.data, node->mName.length );
+						if ( i != 0 )
+						{
+							name.append( "#0" );
+							name.append( i );
+						}
+					}
+
+		}
+	}
 	info.name = make_name( name );
 	info.parent_id = -1;
+	int hack_for_node_anim;
+	if ( is_node_animated() )
+		info.parent_id = index;
+
+
 	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() );
@@ -188,37 +247,20 @@
 nv::assimp_loader::~assimp_loader()
 {
-	if ( m_scene != nullptr ) aiReleaseImport( reinterpret_cast<const aiScene*>( m_scene ) );
-}
-
-bool nv::assimp_loader::load_bones( size_t index, array_ref< data_node_info > bones )
-{
-	if ( m_scene == nullptr ) return false;
-	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
-	const aiMesh*  mesh  = scene->mMeshes[ index ];
-
-	for (unsigned int m=0; m<mesh->mNumBones; m++)
-	{
-		aiBone* bone   = mesh->mBones[m];
-		mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix );
-		const char* name = bone->mName.data;
-		bones[m].name = make_name( name );
-		bones[m].transform = offset;
-	}
-	return true;
+	if ( m_data->scene != nullptr ) aiReleaseImport( m_data->scene );
+	delete m_data;
 }
 
 void nv::assimp_loader::scene_report() const
 {
-	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
-	if ( scene == nullptr ) return;
+	if ( m_data->scene == nullptr ) return;
 
 	NV_LOG_NOTICE( "------------------------" );
-	NV_LOG_NOTICE( "Texture   count - ", scene->mNumTextures );
-	NV_LOG_NOTICE( "Animation count - ", scene->mNumAnimations );
-	NV_LOG_NOTICE( "Material  count - ", scene->mNumMaterials );
-	NV_LOG_NOTICE( "Meshes    count - ", scene->mNumMeshes );
+	NV_LOG_NOTICE( "Texture   count - ", m_data->scene->mNumTextures );
+	NV_LOG_NOTICE( "Animation count - ", m_data->scene->mNumAnimations );
+	NV_LOG_NOTICE( "Material  count - ", m_data->scene->mNumMaterials );
+	NV_LOG_NOTICE( "Meshes    count - ", m_data->scene->mNumMeshes );
 	NV_LOG_NOTICE( "------------------------" );
 
-	aiNode* root = scene->mRootNode;
+	aiNode* root = m_data->scene->mRootNode;
 	if (root)
 	{
@@ -233,11 +275,11 @@
 	NV_LOG_NOTICE( "------------------------" );
 
-	if ( scene->mNumMeshes > 0 )
-	{
-		for ( nv::uint32 mc = 0; mc < scene->mNumMeshes; mc++ )
-		{
-			aiMesh* mesh = scene->mMeshes[mc];
-
-			NV_LOG_NOTICE( "Mesh #", mc, "   - ", string_view( static_cast<char*>( mesh->mName.data ) ) );
+	if ( m_data->scene->mNumMeshes > 0 )
+	{
+		for ( nv::uint32 mc = 0; mc < m_data->scene->mNumMeshes; mc++ )
+		{
+			aiMesh* mesh = m_data->scene->mMeshes[mc];
+
+			NV_LOG_NOTICE( "Mesh #", mc, "   - ", string_view( static_cast<char*>( mesh->mName.data ), mesh->mName.length ) );
 			NV_LOG_NOTICE( "  bones   - ", mesh->mNumBones );
 			NV_LOG_NOTICE( "  uvs     - ", mesh->mNumUVComponents[0] );
@@ -259,4 +301,13 @@
 	NV_LOG_NOTICE( "------------------------" );
 
+	for ( auto node : m_data->nodes )
+	{
+		NV_LOG_NOTICE( "Node : ", string_view( node->mName.data, node->mName.length ) );
+	}
+
+	for ( auto skeleton : m_data->skeletons )
+	{
+		NV_LOG_NOTICE( "Skeleton : ", string_view( skeleton->mName.data, skeleton->mName.length ) );
+	}
 
 	// 	if ( scene->mNumMaterials > 0 )
@@ -283,64 +334,117 @@
 }
 
-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;
+bool nv::assimp_loader::is_node_animated()
+{
+	return is_animated() && m_data->skeletons.empty();
+}
+
+void nv::assimp_loader::build_skeleton( vector< data_node_info >& skeleton, const void* node, int parent_id )
+{
+	const aiNode* ainode = reinterpret_cast<const aiNode*>( node );
+
+	if ( ainode->mNumMeshes > 0 )
+	{
+		int error;
+		int bug_this_works_only_if_before_releasing_meshes;
+
+		nv::uint32 mid = ainode->mMeshes[0];
+		m_mesh_info[mid].parent_id = parent_id;
+		return;
+	}
+
+	string_view name( ainode->mName.data, ainode->mName.length );
+	if ( name.starts_with( '_' ) ) return;
+
+	data_node_info info;
+	info.name      = make_name( name );
+	info.parent_id = parent_id;
+
+	int this_id = skeleton.size();
+	skeleton.push_back( info );
+	for ( unsigned i = 0; i < ainode->mNumChildren; ++i )
+	{
+		build_skeleton( skeleton, ainode->mChildren[i], this_id );
+	}
+}
+
+data_node_list* nv::assimp_loader::release_merged_bones()
+{
+	if ( m_data->skeletons.empty() ) return nullptr;
+	vector< data_node_info > bone_data;
+	hash_store< shash64, uint16 > bone_map;
+
+	{
+		const aiNode* skeleton = m_data->skeletons[0];
+		build_skeleton( bone_data, skeleton, -1 );
+
+		for ( uint32 i = 0; i < bone_data.size(); ++i )
+		{
+			bone_map[bone_data[i].name] = uint16(i);
+		}
+	}
+
 	for ( unsigned int m = 0; m < m_mesh_count; ++m )
 	{
 		uint16 translate[MAX_BONES];
 		vector< data_node_info > bones;
-		const aiMesh*  mesh  = scene->mMeshes[ m ];
+		const aiMesh*  mesh = m_data->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 )
+			for ( unsigned int b = 0; b < mesh->mNumBones; b++ )
 			{
-
-				data_node_info bone = bones[b];
-				auto iname = names.find( bone.name );
-				if ( iname == names.end() )
+				aiBone* bone = mesh->mBones[b];
+				mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix );
+				shash64 bone_name( bone->mName.data );
+
+				int remove_this;
+
+				NV_ASSERT( bone_map.find( shash64( bone->mName.data ) ) != bone_map.end(), "BONE NOT FOUND!" );
+				uint16 index = bone_map[bone_name];
+				bone_data[index].transform = offset;
+				translate[b] = index;
+			}
+
+			data_channel_access< assimp_skinned_vtx > channel( const_cast<raw_data_channel*>( m_meshes[m]->get_channel( 0 ) ) );
+			for ( unsigned v = 0; v < channel.size(); ++v )
+			{
+				assimp_skinned_vtx& vertex = channel.data()[v];
+				for ( int i = 0; i < 4; ++i )
 				{
-					NV_ASSERT( result->size() < MAX_BONES, "Too many bones to merge!" );
-					uint16 index = uint16( result->size() );
-					result->append( bone );
-					names[ bone.name ] = index;
-					translate[b] = index;
-				}
-				else
-				{
-					translate[b] = iname->second;
-				}
-			}
-			if ( m > 0 && bones.size() > 0 )
-			{
-				data_channel_access< assimp_skinned_vtx > channel( const_cast< raw_data_channel* >( meshes[m].get_channel(0) ) );
-				for ( unsigned v = 0; v < channel.size(); ++v )
-				{
-					assimp_skinned_vtx& vertex = channel.data()[v];
-
-					for ( int i = 0 ; i < 4; ++i)
+					if ( vertex.boneweight[i] > 0.0f )
 					{
-						if ( vertex.boneweight[i] > 0.0f ) 
-						{
-							vertex.boneindex[i] = int( translate[vertex.boneindex[i]] );
-						}
+						vertex.boneindex[i] = int( translate[vertex.boneindex[i]] );
 					}
 				}
 			}
-		}	
-	}
-	//result->initialize();
-
-	return result;
+
+		}
+	}
+
+	for ( uint32 i = 0; i < bone_data.size(); ++i )
+	{
+		int error; // not really, just
+		int check_this_shit;
+		if ( bone_data[i].transform == mat4() )
+		{
+			mat4 tr = nv::math::inverse( assimp_mat4_cast( m_data->node_by_name[bone_data[i].name]->mTransformation ) );
+			bone_data[i].transform = tr * bone_data[bone_data[i].parent_id].transform;
+		}
+//		list->append( bone_data[i] );
+	}
+
+
+	data_node_list* list = new data_node_list( make_name( "bones" ) );
+	for ( uint32 i = 0; i < bone_data.size(); ++i )
+	{
+		list->append( bone_data[i] );
+	}
+
+	return list;
 }
 
 mesh_nodes_data* nv::assimp_loader::release_mesh_nodes_data( size_t index /*= 0*/ )
 {
-	if ( m_scene == nullptr ) return nullptr;
-	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
+	if ( m_data->scene == nullptr ) return nullptr;
+	const aiScene* scene = reinterpret_cast<const aiScene*>( m_data->scene );
 	if ( scene->mRootNode == nullptr || scene->mAnimations == nullptr || scene->mAnimations[index] == nullptr) return nullptr;
 
@@ -349,13 +453,20 @@
 
 	uint32 count = count_nodes( scene->mRootNode );
+	count = count - 1;
 
 	uint16 frame_rate     = static_cast<uint16>( anim->mTicksPerSecond );
-	uint16 duration       = static_cast<uint16>( anim->mDuration );
+	uint16 duration       = static_cast<uint16>( anim->mDuration )+1;
 
 	data_channel_set** temp  = new data_channel_set*[ count ];
-	data_node_info*    temp2 = new data_node_info[count];
+	data_node_info*    temp2 = new data_node_info[count ];
 	array_ref< data_channel_set* > temp_ref( temp, count );
 	array_ref< data_node_info >    temp2_ref( temp2, count );
-	load_node( index, temp_ref, temp2_ref, root, 0, -1 );
+
+	nv::sint16 next = 0;
+	for ( unsigned i = 0; i < scene->mRootNode->mNumChildren; ++i )
+	{
+		next = load_node( index, temp_ref, temp2_ref, scene->mRootNode->mChildren[i], next, -1 );
+	}
+//	load_node( index, temp_ref, temp2_ref, scene->mRootNode, 0, -1 );
 
 	mesh_nodes_data* result = new mesh_nodes_data( make_name( static_cast<const char*>( anim->mName.data ) ), frame_rate, duration );
@@ -372,19 +483,25 @@
 data_node_list* nv::assimp_loader::release_data_node_list( size_t index /*= 0 */ )
 {
+	return release_merged_bones();
+}
+
+bool nv::assimp_loader::is_animated( size_t /*= 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;
+	return m_mesh_count == 0 || m_data->scene->mNumAnimations > 0 && m_data->skeletons.size() == 0;
+}
+
+int indent = 0;
+
+void nv::assimp_loader::scan_nodes( const void* node ) const
+{
+	const aiNode* ainode = reinterpret_cast<const aiNode*>( node );
+	m_data->nodes.push_back( ainode );
+	m_data->node_by_name[shash64(ainode->mName.data)] = ainode;
+
+	for ( unsigned i = 0; i < ainode->mNumChildren; ++i )
+	{
+		scan_nodes( ainode->mChildren[i] );
+	}
 }
 
@@ -402,8 +519,7 @@
 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 );
 	const aiNode*  node  = reinterpret_cast<const aiNode*>( vnode );
 	string_view name( static_cast< const char* >( node->mName.data ) );
-	const aiAnimation* anim  = scene->mAnimations[anim_id];
+	const aiAnimation* anim  = m_data->scene->mAnimations[anim_id];
 	const aiNodeAnim*  anode = nullptr;
 
@@ -415,5 +531,8 @@
 	}
 
-	nodes[ this_id ] = anode ? create_keys( anode ) : data_channel_set_creator::create_set( 0 );
+
+	transform t = nv::transform( nv::assimp_mat4_cast( node->mTransformation ) );
+
+	nodes[ this_id ] = anode ? create_keys( anode, t ) : data_channel_set_creator::create_set( 0 );
 
 	infos[this_id].name      = make_name( name );
@@ -424,6 +543,7 @@
 	//       node's without keys
 	// 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();
+//   	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;
@@ -436,12 +556,13 @@
 }
 
-data_channel_set* nv::assimp_loader::create_keys( const void* vnode )
-{
-	const aiNodeAnim* node = reinterpret_cast< const aiNodeAnim* >( vnode );
+data_channel_set* nv::assimp_loader::create_keys( const void* vnode, const transform& tr )
+{
+	const aiNodeAnim* node  = reinterpret_cast< const aiNodeAnim* >( vnode );
 	if ( node->mNumPositionKeys == 0 && node->mNumRotationKeys == 0 && node->mNumScalingKeys == 0 )
 	{
 		return data_channel_set_creator::create_set( 0 );
 	}
-	
+
+/* OLD
 	data_channel_set* set = data_channel_set_creator::create_set( 2 );
 	data_channel_set_creator key_set( set );
@@ -461,4 +582,17 @@
 		rchannel[np].rotation = assimp_quat_cast(node->mRotationKeys[np].mValue );
 	}
+	*/
+	data_channel_set* set = data_channel_set_creator::create_set( 1 );
+	data_channel_set_creator key_set( set );
+
+	assimp_key_tr* channel = key_set.add_channel< assimp_key_tr >( node->mNumPositionKeys ).data();
+	for ( unsigned np = 0; np < node->mNumPositionKeys; ++np )
+	{
+		channel[np].tform.set_position( assimp_vec3_cast( node->mPositionKeys[np].mValue ) );
+		channel[np].tform.set_orientation( assimp_quat_cast( node->mRotationKeys[np].mValue ) );
+		if ( is_node_animated() )
+			channel[np].tform = tr.inverse() * channel[np].tform ;
+	}
+
 // 	if ( node->mNumScalingKeys > 0 )
 // 	{
@@ -503,8 +637,7 @@
 nv::size_t nv::assimp_loader::get_nodes_data_count() const
 {
-	if ( m_scene == nullptr ) return 0;
-	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
-	return scene->mNumAnimations;	
-}
-
-
+	if ( m_data->scene == nullptr ) return 0;
+	return m_data->scene->mNumAnimations;
+}
+
+
