Index: trunk/src/gfx/mesh_creator.cc
===================================================================
--- trunk/src/gfx/mesh_creator.cc	(revision 481)
+++ trunk/src/gfx/mesh_creator.cc	(revision 482)
@@ -13,81 +13,4 @@
 struct nv_key_transform { nv::transform tform; };
 
-void nv::mesh_nodes_creator::pre_transform_keys()
-{
-	if ( m_data->m_flat ) return;
-	merge_keys();
-	uint16 max_frames = 0;
-
-	nv::vector< sint16 > ids;
-	{
-		// TODO: simplify this shit!
-		// The complexity here is that we cannot pre-transform in any order
-		// as the bones depend on previous bones, but ARE NOT IN ORDER
-		// 
-		// Either rewrite this a lot nicer, or sort the bones on creation
-		// by tree-order.
-
-		ids.reserve( m_data->m_data.size() );
-		{
-			nv::vector< sint16 > ids_next;
-			ids_next.reserve( m_data->m_data.size() );
-			ids_next.push_back( -1 );
-			while ( !ids_next.empty() )
-			{
-				sint16 pid = ids_next.back();
-				ids_next.pop_back();
-				for ( sint16 i = 0; i < sint16(m_data->m_data.size()); ++i )
-					if ( m_data->m_data[i]->get_parent_id() == pid )
-					{
-						sint16* it = nv::find( ids.begin(), ids.end(), i );
-						if ( it == ids.end() )
-						{
-							ids.push_back( i );
-							ids_next.push_back( i );
-						}
-					}
-			}
-		}
-
-		if ( ids.size() != m_data->m_data.size() )
-		{
-			NV_LOG_WARNING( "Bad skeleton!" );
-		}
-	}
-
-	NV_LOG_DEBUG( "ID/PID" );
-	for ( auto id : ids )
-	{
-		data_channel_set* keys = m_data->m_data[id];
-		sint16 parent_id = keys->get_parent_id();
-		NV_LOG_DEBUG( "Id : ", id, " PID", 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 );
-		max_frames = nv::max<uint16>( uint16( count ), max_frames );
-		if ( pkeys && pkeys->size() > 0 && keys && keys->size() > 0 )
-		{
-			data_channel_access< nv_key_transform > channel_creator( keys, 0 );
-
-			nv_key_transform* channel = channel_creator.data();
-			const nv_key_transform* pchannel = pkeys->get_channel(0)->data_cast< nv_key_transform >();
-			for ( unsigned n = 0; n < count; ++n )
-			{
-				channel[n].tform = pchannel[ nv::min( n, pcount-1 ) ].tform * channel[n].tform;
-			}
-		}
-	}
-
-	// DAE pre_transform hack
-	if ( m_data->m_frame_rate == 1 )
-	{
-		m_data->m_frame_rate  = 32;
-		m_data->m_frame_count = max_frames;
-	}
-
-	m_data->m_flat = true;
-}
-
-
 void nv::mesh_nodes_creator::merge_keys()
 {
@@ -110,7 +33,4 @@
 			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 ) );
 
@@ -145,6 +65,4 @@
 	for ( auto node : m_data->m_data )
 	{
-		node->m_transform = pre_transform * node->m_transform * post_transform;
-
 		for ( size_t c = 0; c < node->size(); ++c )
 		{
@@ -158,4 +76,15 @@
 	}
 }
+
+void nv::data_node_list_creator::transform( float scale, const mat3& r33 )
+{
+	mat3 ri33 = math::inverse( r33 );
+	mat4 pre_transform( scale * r33 );
+	mat4 post_transform( 1.f / scale * ri33 );
+
+	for ( auto& node : m_data->m_data )
+		node.transform = pre_transform * node.transform * post_transform;
+}
+
 
 void nv::mesh_data_creator::transform( float scale, const mat3& r33 )
@@ -209,4 +138,5 @@
 	nv::vec4 tangent;
 };
+
 
 void nv::mesh_data_creator::flip_normals()
@@ -434,4 +364,5 @@
 }
 
+
 template < typename T >
 static inline void swap_culling_impl( nv::raw_data_channel* index_channel )
@@ -650,3 +581,2 @@
 	initialize();
 }
-
Index: trunk/src/gfx/skeleton_instance.cc
===================================================================
--- trunk/src/gfx/skeleton_instance.cc	(revision 481)
+++ trunk/src/gfx/skeleton_instance.cc	(revision 482)
@@ -9,5 +9,5 @@
 #include "nv/core/profiler.hh"
 
-void nv::skeleton_binding::prepare( const mesh_nodes_data* node_data, const mesh_nodes_data* bone_data )
+void nv::skeleton_binding::prepare( const mesh_nodes_data* node_data, const data_node_list& bone_data )
 {
 	if ( m_indices.empty() )
@@ -16,17 +16,12 @@
 		hash_store< shash64, uint16 > bone_names;
 		m_indices.resize( node_data->size() );
-		
-		for ( nv::uint16 bi = 0; bi < bone_data->size(); ++bi )
-		{
-			const data_channel_set* bone = ( *bone_data )[bi];
-			bone_names[bone->get_name()] = bi;
-		}
+
+		for ( nv::uint16 bi = 0; bi < bone_data.size(); ++bi )
+			bone_names[bone_data[bi].name] = bi;
 
 		for ( uint32 n = 0; n < node_data->size(); ++n )
 		{
-			const data_channel_set* node = ( *node_data )[n];
 			sint16 bone_id = -1;
-
-			auto bi = bone_names.find( node->get_name() );
+			auto bi = bone_names.find( node_data->get_info( n ).name );
 			if ( bi != bone_names.end() )
 			{
@@ -36,5 +31,5 @@
 
 		}
-		m_bone_count = bone_data->size();
+		m_bone_count = bone_data.size();
 	}
 
@@ -48,69 +43,5 @@
 			}
 	}
-
-
 }
-
-// void nv::skeleton_instance::animate_( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame )
-// {
-// 	if ( m_matrix.size() > 0 )
-// 	{
-// 		if ( node_data->is_flat() )
-// 		{
-// 			animate_flat( node_data, binding, frame );
-// 		}
-// 		else
-// 		{
-// 			for ( uint32 n = 0; n < node_data->size(); ++n )
-// 				if ( ( *node_data )[n]->get_parent_id() == -1 )
-// 					animate_rec( node_data, binding, frame, n, transform() );
-// 		}
-// 	}
-// }
-// 
-// void nv::skeleton_instance::animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent )
-// {
-// 	// TODO: fix transforms, which are now embedded,
-// 	//       see note in assimp_loader.cc:load_node
-// 	const data_channel_set* node = ( *node_data )[id];
-// 	transform node_mat( node->get_transform() );
-// 
-// 	if ( node->size() > 0 )
-// 	{
-// 		raw_channel_interpolator interpolator( node, binding.m_key );
-// 		node_mat = interpolator.get< transform >( frame );
-// 	}
-// 
-// 	transform global_mat = parent * node_mat;
-// 
-//  	sint16 bone_id = binding.m_indices[id];
-//  	if ( bone_id >= 0 )
-//  	{
-//  		m_matrix[bone_id] = global_mat.extract() * binding.m_offsets[bone_id];
-//  	}
-// 
-// 	for ( auto child : node_data->children( id ) )
-// 	{
-// 		animate_rec( node_data, binding, frame, child, global_mat );
-// 	}
-// }
-// 
-// void nv::skeleton_instance::animate_flat( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame ) 
-// {
-// 	for ( uint32 n = 0; n < node_data->size(); ++n )
-// 		if ( binding.m_indices[n] >= 0 )
-// 		{
-// 			const data_channel_set* node = ( *node_data )[n];
-// 			nv::mat4 node_mat( node->get_transform() );
-// 
-// 			if ( node->size() > 0 )
-// 			{
-// 				raw_channel_interpolator interpolator( node, binding.m_key );
-// 				node_mat = interpolator.get< mat4 >( frame );
-// 			}
-// 			sint16 bone_id = binding.m_indices[n];
-// 			m_matrix[bone_id] = node_mat * binding.m_offsets[bone_id];
-// 		}
-// }
 
 void nv::skeleton_instance::assign( const skeleton_transforms& skeleton, const bone_transforms& bones )
@@ -120,5 +51,7 @@
 	const transform* transforms = skeleton.transforms();
 	for ( uint32 n = 0; n < skeleton.size(); ++n )
+	{
 		m_matrix[n] = transforms[n].extract() * bones.m_offsets[n];
+	}
 }
 
@@ -129,8 +62,82 @@
 }
 
-void nv::skeleton_transforms::animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent )
+void nv::skeleton_transforms::animate_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame )
+{
+	if ( m_transforms.size() != binding.skeleton_size() )
+		m_transforms.resize( binding.skeleton_size() );
+	for ( uint32 n = 0; n < node_data->size(); ++n )
+	{
+		const data_channel_set* node = ( *node_data )[n];
+		sint16 bone_id = binding.m_indices[n];
+		if ( bone_id >= 0 )
+		{
+			if ( node->size() > 0 )
+				m_transforms[bone_id] = raw_channel_interpolator( node, binding.m_key ).get< transform >( frame );
+			int confirm_that_not_needed;
+// 			else
+// 				m_transforms[bone_id] = transform( node->get_transform() );
+		}
+	}
+}
+
+void nv::skeleton_transforms::blend_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, float blend )
+{
+	if ( m_transforms.size() != binding.skeleton_size() )
+		m_transforms.resize( binding.skeleton_size() );
+	for ( uint32 n = 0; n < node_data->size(); ++n )
+	{
+		const data_channel_set* node = ( *node_data )[n];
+		sint16 bone_id = binding.m_indices[n];
+		if ( bone_id >= 0 )
+		{
+			
+			transform tr = node->size() > 0 ? raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ) : transform( /*node->get_transform()*/ ); int confirm_that_not_needed;
+			m_transforms[bone_id] = nv::interpolate( m_transforms[bone_id], tr, blend );
+		}
+	}
+}
+
+void nv::skeleton_transforms::delocalize_rec( const data_node_tree& node_data, const skeleton_binding& binding, uint32 id, const transform& parent )
+{
+	sint16 bone_id = binding.m_indices[id];
+	transform global_mat = parent;
+	if ( bone_id >= 0 )
+	{
+		global_mat *= m_transforms[bone_id];
+		m_transforms[bone_id] = global_mat;
+	}
+	for ( auto child : node_data.children( id ) )
+	{
+		delocalize_rec( node_data, binding, child, global_mat );
+	}
+}
+
+void nv::skeleton_transforms::animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local )
 {
 	const data_channel_set* node = ( *node_data )[id];
-	transform node_mat( node->get_transform() );
+	transform node_mat;
+
+	if ( node->size() > 0 )
+		node_mat = raw_channel_interpolator( node, binding.m_key ).get< transform >( frame );
+	int confirm_that_not_needed;
+	// 	else
+// 		node_mat = transform( node->get_transform() );
+	sint16 bone_id = binding.m_indices[id];
+	transform global_mat = parent * node_mat;
+	if ( bone_id >= 0 )
+	{
+		m_transforms[bone_id] = local ? node_mat : global_mat;
+	}
+	for ( auto child : node_data->children( id ) )
+	{
+		animate_rec( node_data, binding, frame, child, global_mat, local );
+	}
+}
+
+void nv::skeleton_transforms::blend_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local, float blend )
+{
+	const data_channel_set* node = ( *node_data )[id];
+	int confirm_that_not_needed;
+	transform node_mat/*( node->get_transform() )*/;
 
 	if ( node->size() > 0 )
@@ -143,23 +150,21 @@
 	if ( bone_id >= 0 )
 	{
-		m_transforms[bone_id] = global_mat;
+		m_transforms[bone_id] = nv::interpolate( m_transforms[bone_id], local ? node_mat : global_mat, blend );
 	}
 	for ( auto child : node_data->children( id ) )
 	{
-		animate_rec( node_data, binding, frame, child, global_mat );
+		blend_rec( node_data, binding, frame, child, global_mat, local, blend );
 	}
 }
 
-void nv::bone_transforms::prepare( const mesh_nodes_data* bone_data )
+
+void nv::bone_transforms::prepare( const data_node_list& bone_data )
 {
 	if ( m_offsets.empty() )
 	{
-		m_offsets.resize( bone_data->size() );
+		m_offsets.resize( bone_data.size() );
 
-		for ( nv::uint16 bi = 0; bi < bone_data->size(); ++bi )
-		{
-			const data_channel_set* bone = ( *bone_data )[bi];
-			m_offsets[bi] = bone->get_transform();
-		}
+		for ( nv::uint16 bi = 0; bi < bone_data.size(); ++bi )
+			m_offsets[bi] = bone_data[bi].transform;
 	}
 }
