Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 469)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 470)
@@ -72,29 +72,33 @@
 }
 
-void nv::keyframed_mesh::update_animation( animation_entry* anim, uint32 a_anim_time )
+void nv::keyframed_mesh::update_animation( animation_entry* anim, uint32 a_ms_anim_time )
 {
 	if ( m_active )
 	{
-		float tick_time = ( static_cast<float>( a_anim_time ) * 0.001f ) * anim->get_frame_rate();
-		float duration  = anim->is_looping() ? anim->get_duration() + 1.0f : anim->get_duration();
-		if ( tick_time >= duration )
+		float  fframe   = ( static_cast<float>( a_ms_anim_time ) * 0.001f ) * anim->get_fps();
+		uint32 frame    = uint32( fframe );
+		float  reminder = fframe - static_cast<float>( frame );
+		uint32 duration = anim->is_looping() ? anim->get_frame_count() + 1 : anim->get_frame_count();
+
+		if ( frame >= duration )
 		{
 			if ( anim->is_looping() )
 			{
-				tick_time = fmodf( tick_time, duration );
+				frame  = frame % duration;
+				fframe = static_cast<float>( frame ) + reminder;
 			}
 			else
 			{
-				m_active     = false;
-				m_last_frame = static_cast<uint32>( anim->get_end() );
-				m_next_frame = m_last_frame;
+				m_active        = false;
+				m_last_frame    = anim->get_end_frame();
+				m_next_frame    = m_last_frame;
 				m_interpolation = 0.0f;
 				return;
 			}
 		}
-		m_last_frame    = static_cast<uint32>( math::floor( tick_time ) + anim->get_start() );
+		m_last_frame    = frame + anim->get_start_frame();
 		m_next_frame    = m_last_frame + 1;
-		if ( m_next_frame > static_cast<uint32>( anim->get_end() ) ) m_next_frame = static_cast<uint32>( anim->get_start() );
-		m_interpolation = tick_time - math::floor( tick_time );
+		if ( m_next_frame > anim->get_end_frame() ) m_next_frame = anim->get_start_frame();
+		m_interpolation = reminder;
 	}
 }
Index: trunk/src/gfx/mesh_creator.cc
===================================================================
--- trunk/src/gfx/mesh_creator.cc	(revision 469)
+++ trunk/src/gfx/mesh_creator.cc	(revision 470)
@@ -9,4 +9,6 @@
 #include "nv/interface/data_channel_access.hh"
 
+#include "nv/core/logging.hh"
+
 struct nv_key_transform { nv::transform tform; };
 
@@ -16,8 +18,49 @@
 	merge_keys();
 	uint32 max_frames = 0;
-	for ( auto keys : m_data->m_data )
-	{
+
+	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();
-		data_channel_set* pkeys  = ( parent_id != -1 ? m_data->m_data[parent_id] : nullptr );
+		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 );
@@ -26,4 +69,5 @@
 		{
 			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 >();
@@ -38,6 +82,6 @@
 	if ( m_data->m_frame_rate == 1 )
 	{
-		m_data->m_frame_rate = 32;
-		m_data->m_duration   = static_cast<float>( max_frames );
+		m_data->m_frame_rate  = 32;
+		m_data->m_frame_count = max_frames;
 	}
 
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 469)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 470)
@@ -13,4 +13,5 @@
 void nv::skeletal_animation_entry::initialize()
 {
+	m_root      = uint32(-1);
 	m_prepared  = false;
 	m_children  = nullptr;
@@ -30,17 +31,53 @@
 				m_children[ node->get_parent_id()].push_back( n );
 			}
-		}
-	}
-}
-
-void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 time ) const
-{
-	float tick_time = ( time * 0.001f ) * m_frame_rate;
-	float anim_time = m_start;
-	if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
+			else
+			{
+				if ( m_root >= 0 )
+				{
+					m_root = uint32( -2 );
+				}
+				else
+					m_root = n;
+			}
+		}
+		NV_ASSERT( m_root != uint32( -1 ), "Animation without root!" );
+	}
+}
+
+void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 a_ms_time ) const
+{
+	float  fframe   = ( a_ms_time * 0.001f ) * m_fps;
+	uint32 frame    = math::floor( fframe );
+	float  reminder = fframe - static_cast<float>( frame );
+	uint32 duration = get_frame_count();
+	if ( duration == 0 )
+	{
+		frame  = get_start_frame();
+		fframe = static_cast<float>( frame );
+	}
+	else if ( frame >= duration )
+	{
+		if ( is_looping() )
+		{
+			frame  = frame % duration;
+			fframe = static_cast<float>( frame ) + reminder;
+		}
+		else
+		{
+			frame  = get_end_frame();
+			fframe = static_cast<float>( frame );
+		}
+	}
 
 	if ( !m_node_data->is_flat() )
 	{
-		animate_rec( data, anim_time, 0, mat4() );
+		if ( m_root == uint32( -2 ) ) // multi-root
+		{
+			for ( uint32 n = 0; n < m_node_data->size(); ++n )
+				if ( ( *m_node_data )[n]->get_parent_id() == -1 )
+					animate_rec( data, fframe, n, mat4() );
+		}
+		else
+			animate_rec( data, fframe, m_root, mat4() );
 		return;
 	}
@@ -55,5 +92,5 @@
 			{
 				raw_channel_interpolator interpolator( node, m_interpolation_key );
-				node_mat = interpolator.get< mat4 >( anim_time );
+				node_mat = interpolator.get< mat4 >( fframe );
 			}
 
@@ -66,10 +103,10 @@
 {
 	if ( m_prepared ) return;
-	unordered_map< uint64, uint16 > bone_names;
+	nv::hash_store< shash64, uint16 > bone_names;
 	m_offsets = new mat4[ bones->size() ];
 	for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
 	{
 		const data_channel_set* bone = (*bones)[ bi ];
-		bone_names[ bone->get_name().value() ] = bi;
+		bone_names[ bone->get_name() ] = bi;
 		m_offsets[bi] = bone->get_transform();
 	}
@@ -80,5 +117,5 @@
 		sint16 bone_id = -1;
 
-		auto bi = bone_names.find( node->get_name().value() );
+		auto bi = bone_names.find( node->get_name() );
 		if ( bi != bone_names.end() )
 		{
@@ -129,5 +166,5 @@
 
 nv::skeletal_mesh::skeletal_mesh( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
-	: m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr )
+	: m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr ), m_parent_id(-1)
 {
 	if ( a_mesh )
@@ -135,4 +172,5 @@
 		m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
 		m_index_count = a_mesh->get_channel_size( slot::INDEX );
+		m_parent_id = a_mesh->get_parent_id();
 	}
 	if ( m_bone_data )
