Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 288)
+++ trunk/src/formats/md3_loader.cc	(revision 289)
@@ -417,5 +417,5 @@
 		nodes[i].parent_id = -1;
 		nodes[i].target_id = -1;
-		nodes[i].data = new key_data;
+		nodes[i].data      = new key_data;
 	
 		key_raw_channel* keys = load_tags( name );
Index: trunk/src/formats/md5_loader.cc
===================================================================
--- trunk/src/formats/md5_loader.cc	(revision 288)
+++ trunk/src/formats/md5_loader.cc	(revision 289)
@@ -14,6 +14,4 @@
 using namespace nv;
 
-// based on http://tfc.duke.free.fr/coding/md5-specs-en.html
-
 static void next_line( std::istream& stream )
 {
@@ -29,5 +27,4 @@
 }
 
-
 static void remove_quotes( std::string& str )
 {
@@ -44,8 +41,21 @@
 bool md5_loader::load( stream& source )
 {
+	reset();
 	std_stream sstream( &source );
 	std::string command;
+	mesh_node_data* nodes = nullptr;
+	size_t num_joints = 0;
+
+	// MESH data
 	dynamic_array< md5_weight > weights;
 	dynamic_array< md5_weight_info > weight_info;
+	size_t num_meshes = 0;
+
+	// MESH data
+	std::vector<md5_joint_info> joint_infos;
+	std::vector<transform>      base_frames;
+	size_t num_animated_components = 0;
+	size_t frame_rate = 0;
+	size_t num_frames = 0;
 
 	sstream >> command;
@@ -63,29 +73,59 @@
 		else if ( command == "numJoints" )
 		{
-			sstream >> m_num_joints;
-			m_joints.resize( m_num_joints );
+			sstream >> num_joints;
+			next_line( sstream ); 
 		}
 		else if ( command == "numMeshes" )
 		{
-			sstream >> m_num_meshes;
-			m_meshes.resize( m_num_meshes );
-			m_num_meshes = 0;
+			assert( m_type == UNKNOWN );
+			m_type = MESH;
+			sstream >> num_meshes;
+			m_meshes.resize( num_meshes );
+			num_meshes = 0;
+		}
+		else if ( command == "numFrames" )
+		{
+			assert( m_type == UNKNOWN || m_type == ANIMATION );
+			m_type = ANIMATION;
+			sstream >> num_frames;
+			next_line( sstream ); 
+		}
+		else if ( command == "frameRate" )
+		{
+			assert( m_type == UNKNOWN || m_type == ANIMATION );
+			m_type = ANIMATION;
+			sstream >> frame_rate;
+			next_line( sstream ); 
+		}
+		else if ( command == "numAnimatedComponents" )
+		{
+			assert( m_type == UNKNOWN || m_type == ANIMATION );
+			m_type = ANIMATION;
+			sstream >> num_animated_components;
+			next_line( sstream ); 
 		}
 		else if ( command == "joints" )
 		{
+			assert( m_type == MESH );
+			assert( m_nodes == nullptr );
+			nodes = new mesh_node_data[ num_joints ];
+			m_nodes = new mesh_nodes_data( "md5_bones", num_joints, nodes );
 			discard( sstream, "{" );
-			md5_joint joint;
-			for ( size_t i = 0; i < m_num_joints; ++i )
-			{
-				int parent_id;
-				sstream >> joint.name >> parent_id;
+			for ( size_t i = 0; i < m_nodes->get_count(); ++i )
+			{
+				sstream >> nodes[i].name >> nodes[i].parent_id;
+				vec3 pos;
+				quat orient;
 				discard( sstream, "(" );
-				sstream >> joint.pos.x >> joint.pos.y >> joint.pos.z;
+				sstream >> pos.x >> pos.y >> pos.z;
 				discard( sstream, ")" );
 				discard( sstream, "(" );
-				sstream >> joint.orient.x >> joint.orient.y >> joint.orient.z;
-				remove_quotes( joint.name );
-				unit_quat_w( joint.orient );
-				m_joints[i] = joint;
+				sstream >> orient.x >> orient.y >> orient.z;
+				unit_quat_w( orient );
+				remove_quotes( nodes[i].name );
+				nodes[i].target_id       = -1;
+				nodes[i].parent_id       = -1;
+				nodes[i].transform       = transform( pos, orient ).inverse().extract();
+				nodes[i].data            = nullptr;
 				next_line( sstream );
 			}
@@ -94,4 +134,5 @@
 		else if ( command == "mesh" )
 		{
+			assert( m_type == MESH );
 			mesh_data* mesh = new mesh_data("md5_mesh");
 
@@ -192,9 +233,97 @@
 			}
 
-			prepare_mesh( weight_info.size(), mesh, weights.data(), weight_info.data() );
-
-			m_meshes[ m_num_meshes ] = mesh;
-			m_num_meshes++;
-		}
+			prepare_mesh( nodes, weight_info.size(), mesh, weights.data(), weight_info.data() );
+
+			m_meshes[ num_meshes ] = mesh;
+			num_meshes++;
+		} // mesh
+		else if ( command == "hierarchy" )
+		{
+			assert( m_type == ANIMATION );
+			assert( nodes == nullptr );
+			nodes = new mesh_node_data[ num_joints ];
+			m_nodes = new mesh_nodes_data( "md5_animation", num_joints, nodes, (nv::uint16)frame_rate, (float)num_frames, true );
+			joint_infos.resize( num_joints );
+
+			discard( sstream, "{" );
+			for ( size_t i = 0; i < m_nodes->get_count(); ++i )
+			{
+				std::string    name;
+				sstream >> nodes[i].name >> nodes[i].parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
+				remove_quotes( name );
+				nodes[i].transform = mat4();
+				nodes[i].target_id = -1;
+				nodes[i].data      = new key_data;
+				nodes[i].data->add_channel( key_raw_channel::create< md5_key_t >( num_frames ) );
+				next_line( sstream ); 
+			}
+			discard( sstream, "}" );
+		}
+		else if ( command == "bounds" )
+		{
+			assert( m_type == ANIMATION );
+			discard( sstream, "{" );
+			next_line( sstream ); 
+			for ( size_t i = 0; i < num_frames; ++i ) 
+			{
+				//  				vec3 min;
+				//  				vec3 max;
+				//  				discard( sstream, "(" );
+				//  				sstream >> min.x >> min.y >> min.z;
+				//  				discard( sstream, ")" );
+				//  				discard( sstream, "(" );
+				//  				sstream >> max.x >> max.y >> max.z;
+				// 				m_bounds.push_back( bound );
+				next_line( sstream ); 
+			}
+
+			discard( sstream, "}" );
+			next_line( sstream ); 
+		}
+		else if ( command == "baseframe" )
+		{
+			assert( m_type == ANIMATION );
+			discard( sstream, "{" );
+			next_line( sstream ); 
+
+			for ( size_t i = 0; i < m_nodes->get_count(); ++i )
+			{
+				transform base_frame;
+				vec3 pos;
+				quat orient;
+				discard( sstream, "(" );
+				sstream >> pos.x >> pos.y >> pos.z;
+				discard( sstream, ")" );
+				discard( sstream, "(" );
+				sstream >> orient.x >> orient.y >> orient.z;
+				next_line( sstream ); 
+
+				base_frames.emplace_back( pos, orient );
+			}
+			discard( sstream, "}" );
+			next_line( sstream ); 
+		}
+		else if ( command == "frame" )
+		{
+			std::vector<float> frame;
+			uint32 frame_id;
+			sstream >> frame_id;
+			discard( sstream, "{" );
+			next_line( sstream ); 
+
+			frame.reserve( num_animated_components );
+			char buf[50];
+			for ( size_t i = 0; i < num_animated_components; ++i )
+			{
+				sstream >> buf;
+				frame.push_back((float)atof(buf));
+			}
+
+			build_frame_skeleton( nodes, frame_id, joint_infos, base_frames, frame );
+
+			discard( sstream, "}" );
+			next_line( sstream ); 
+		}
+
 		sstream >> command;
 	}
@@ -203,6 +332,7 @@
 }
 
-bool md5_loader::prepare_mesh( uint32 vtx_count, mesh_data* mdata, md5_weight* weights, md5_weight_info* weight_info )
-{
+bool md5_loader::prepare_mesh( mesh_node_data* nodes, uint32 vtx_count, mesh_data* mdata, md5_weight* weights, md5_weight_info* weight_info )
+{
+	assert( m_type == MESH );
 	md5_vtx_pnt* vtcs = (md5_vtx_pnt*)mdata->get_channel< md5_vtx_pnt >()->data; 
 	md5_vtx_pntiw* vtx_data = (md5_vtx_pntiw*)mdata->get_channel< md5_vtx_pntiw >()->data; 
@@ -254,9 +384,10 @@
 			if ( j < weight_count )
 			{
-				md5_weight& weight = weights[start_weight + j];
-				md5_joint&  joint  = m_joints[weight.joint_id];
-				glm::vec3 rot_pos = joint.orient * weight.pos;
-
-				vtc.position += ( joint.pos + rot_pos ) * weight.bias;
+				md5_weight& weight           = weights[start_weight + j];
+				const mesh_node_data&  joint = nodes[weight.joint_id];
+				const transform tr = transform( joint.transform ).inverse();
+				glm::vec3 rot_pos = tr.get_orientation() * weight.pos;
+
+				vtc.position += ( tr.get_position() + rot_pos ) * weight.bias;
 			}
 		}
@@ -317,7 +448,8 @@
  		for ( size_t j = 0; j < 4; ++j )
  		{
- 			const md5_joint&  joint  = m_joints[vdata.boneindex[j]];
- 			vdata.normal  += ( normal  * joint.orient ) * vdata.boneweight[j];
- 			vdata.tangent += ( tangent * joint.orient ) * vdata.boneweight[j];
+			const mesh_node_data&  joint = nodes[vdata.boneindex[j]];
+			const transform tr = transform( joint.transform ).inverse();
+ 			vdata.normal  += ( normal  * tr.get_orientation() ) * vdata.boneweight[j];
+ 			vdata.tangent += ( tangent * tr.get_orientation() ) * vdata.boneweight[j];
  		}
 	}
@@ -326,174 +458,7 @@
 }
 
-
-md5_animation::md5_animation()
-	: m_md5_version( 0 )
-	, m_num_frames( 0 )
-	, m_num_joints( 0 )
-	, m_frame_rate( 0 )
-	, m_num_animated_components( 0 )
-	, m_anim_duration( 0 )
-	, m_frame_duration( 0 )
-{
-
-}
-
-md5_animation::~md5_animation()
-{
-
-}
-
-bool md5_animation::load_animation( stream& source )
-{
-	std::vector<md5_joint_info> joint_infos;
-	std::vector<transform>      base_frames;
-	m_num_frames = 0;
-
-	std_stream sstream( &source );
-	std::string command;
-
-	sstream >> command;
-	while ( !sstream.eof() )
-	{
-		if ( command == "MD5Version" )
-		{
-			sstream >> m_md5_version;
-			assert( m_md5_version == 10 );
-		}
-		else if ( command == "commandline" )
-		{
-			next_line( sstream ); 
-		}
-		else if ( command == "numFrames" )
-		{
-			sstream >> m_num_frames;
-			next_line( sstream ); 
-		}
-		else if ( command == "numJoints" )
-		{
-			sstream >> m_num_joints;
-			m_joints.reserve( m_num_joints );
-			next_line( sstream ); 
-		}
-		else if ( command == "frameRate" )
-		{
-			sstream >> m_frame_rate;
-			next_line( sstream ); 
-		}
-		else if ( command == "numAnimatedComponents" )
-		{
-			sstream >> m_num_animated_components;
-			next_line( sstream ); 
-		}
-		else if ( command == "hierarchy" )
-		{
-			discard( sstream, "{" );
-			for ( size_t i = 0; i < m_num_joints; ++i )
-			{
-				md5_joint_info joint;
-				sstream >> joint.name >> joint.parent_id >> joint.flags >> joint.start_index;
-				remove_quotes( joint.name );
-				joint_infos.push_back( joint );
-				m_joints.emplace_back( joint.parent_id );
-				next_line( sstream ); 
-			}
-			discard( sstream, "}" );
-		}
-		else if ( command == "bounds" )
-		{
-			discard( sstream, "{" );
-			next_line( sstream ); 
-			for ( size_t i = 0; i < m_num_frames; ++i ) 
-			{
-//  				vec3 min;
-//  				vec3 max;
-//  				discard( sstream, "(" );
-//  				sstream >> min.x >> min.y >> min.z;
-//  				discard( sstream, ")" );
-//  				discard( sstream, "(" );
-//  				sstream >> max.x >> max.y >> max.z;
-// 				m_bounds.push_back( bound );
-				next_line( sstream ); 
-			}
-
-			discard( sstream, "}" );
-			next_line( sstream ); 
-		}
-		else if ( command == "baseframe" )
-		{
-			discard( sstream, "{" );
-			next_line( sstream ); 
-
-			for ( size_t i = 0; i < m_num_joints; ++i )
-			{
-				transform base_frame;
-				vec3 pos;
-				quat orient;
-				discard( sstream, "(" );
-				sstream >> pos.x >> pos.y >> pos.z;
-				discard( sstream, ")" );
-				discard( sstream, "(" );
-				sstream >> orient.x >> orient.y >> orient.z;
-				next_line( sstream ); 
-
-				base_frames.emplace_back( pos, orient );
-			}
-			discard( sstream, "}" );
-			next_line( sstream ); 
-		}
-		else if ( command == "frame" )
-		{
-			std::vector<float> frame;
-			int frame_id;
-			sstream >> frame_id;
-			discard( sstream, "{" );
-			next_line( sstream ); 
-
-			frame.reserve( m_num_animated_components );
-			char buf[50];
-			for ( size_t i = 0; i < m_num_animated_components; ++i )
-			{
-				sstream >> buf;
-				frame.push_back((float)atof(buf));
-			}
-
-			build_frame_skeleton( joint_infos, base_frames, frame );
-
-			discard( sstream, "}" );
-			next_line( sstream ); 
-		}
-
-		sstream >> command;
-	} 
-
-
-	m_frame_duration = 1.0f / (float)m_frame_rate;
-	m_anim_duration = ( m_frame_duration * (float)m_num_frames );
-
-	return true;
-}
-
-
-void nv::md5_animation::update_skeleton( transform* skeleton, float anim_time ) const
-{
-	anim_time = glm::clamp( anim_time, 0.0f, m_anim_duration );
-	float frame_num = anim_time * (float)m_frame_rate;
-	size_t frame0 = (size_t)floorf( frame_num );
-	size_t frame1 = (size_t)ceilf( frame_num );
-	frame0 = frame0 % m_num_frames;
-	frame1 = frame1 % m_num_frames;
-
-	float interpolation = fmodf( anim_time, m_frame_duration ) / m_frame_duration;
-
-	for ( size_t i = 0; i < m_num_joints; ++i )
-	{
-		const std::vector< transform >& keys = m_joints[i].keys;
-		skeleton[i] = interpolate( keys[frame0], keys[frame1], interpolation );
-	}
-}
-
-void md5_animation::build_frame_skeleton( const std::vector<md5_joint_info>& joint_infos, const std::vector<transform>& base_frames, const std::vector<float>& frame_data )
-{
-	size_t index = m_joints[0].keys.size();
+void md5_loader::build_frame_skeleton( mesh_node_data* nodes, uint32 index, const std::vector<md5_joint_info>& joint_infos, const std::vector<transform>& base_frames, const std::vector<float>& frame_data )
+{
+	assert( m_type == ANIMATION );
 	for ( unsigned int i = 0; i < joint_infos.size(); ++i )
 	{
@@ -501,7 +466,6 @@
 
 		const md5_joint_info& jinfo = joint_infos[i];
-
-
-		int parent_id = jinfo.parent_id;
+		mesh_node_data& joint = nodes[i];
+		int parent_id         = joint.parent_id;
 
 		vec3 pos    = base_frames[i].get_position();
@@ -517,7 +481,8 @@
 		if ( parent_id >= 0 ) // Has a parent joint
 		{
-			const std::vector< transform >& ptv = m_joints[ size_t( parent_id ) ].keys;
+			const mesh_node_data& pjoint = nodes[parent_id];
+			const transform* ptv = (const transform*)pjoint.data->get_channel(0)->data;
 			transform ptr;
-			if ( ptv.size() > index ) ptr = ptv[ index ];
+			if ( pjoint.data->get_channel(0)->count > index ) ptr = ptv[ index ];
 			glm::vec3 rot_pos = ptr.get_orientation() * pos;
 
@@ -528,5 +493,5 @@
 		}
 
-		m_joints[i].keys.push_back( transform( pos, orient ) );
+		((transform*)joint.data->get_channel(0)->data)[index] = transform( pos, orient );
 	}
 }
@@ -541,15 +506,7 @@
 mesh_nodes_data* nv::md5_loader::release_mesh_nodes_data()
 {
-	mesh_node_data* nodes = new mesh_node_data[ m_num_joints ];
-	for ( uint32 i = 0; i < m_num_joints; ++i )
-	{
-		mesh_node_data& node = nodes[i];
-		node.name      = m_joints[i].name;
-		node.target_id = -1;
-		node.parent_id = -1;
-		node.transform = transform( m_joints[i].pos, m_joints[i].orient ).inverse().extract();
-		node.data      = nullptr;
-	}
-	return new mesh_nodes_data( "nodes", m_num_joints, nodes );
+	mesh_nodes_data* nodes = m_nodes;
+	m_nodes = nullptr; 
+	return nodes;
 }
 
@@ -570,5 +527,13 @@
 nv::md5_loader::~md5_loader()
 {
+	reset();
+}
+
+void nv::md5_loader::reset()
+{
+	if ( m_nodes ) delete m_nodes;
 	for ( auto m : m_meshes ) { if (m) delete m; }
-}
-
+	m_meshes.resize(0);
+	m_nodes = nullptr;
+}
+
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 288)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 289)
@@ -18,4 +18,6 @@
 	m_pntdata.assign( (const md5_vtx_pnt*)pnt_chan->data, pnt_chan->count );
 	m_bone_offset.resize( bones->get_count() );
+	m_transform.resize( bones->get_count() );
+
 	for ( uint32 i = 0; i < bones->get_count(); ++i )
 	{
@@ -32,10 +34,5 @@
 	{
 		skeletal_animation_entry * anim = (skeletal_animation_entry*)a_anim;
-		float frame_duration = 1000.f / (float)anim->get_frame_rate();
-		float anim_duration = frame_duration * anim->get_duration();
-		float new_time = fmodf( (float)a_anim_time, anim_duration );
-		anim->update_skeleton( m_transform.data(), new_time * 0.001f );
-
-		//m_mesh_data->apply( m_transform.data() );
+		anim->update_skeleton( m_transform.data(), (float)a_anim_time );
 		{
 			size_t skeleton_size = m_bone_offset.size();
@@ -72,4 +69,20 @@
 }
 
+
+void nv::skeletal_animation_entry::update_skeleton( transform* skeleton, float time ) const
+{
+	float frame_duration = 1000.f / (float)m_node_data->get_frame_rate();
+	float anim_duration = frame_duration * m_node_data->get_duration();
+	float new_time = fmodf( time, anim_duration ) * 0.001f;
+
+	float frame_num = new_time * m_node_data->get_frame_rate();
+	for ( size_t i = 0; i < m_node_data->get_count(); ++i )
+	{
+		skeleton[i] = m_node_data->get_node(i)->data->get_transform( frame_num );
+	}
+}
+
+
+
 nv::skeletal_mesh::~skeletal_mesh()
 {
@@ -81,6 +94,4 @@
 	if ( a_anim != nullptr )
 	{
-		skeletal_animation_entry * anim = (skeletal_animation_entry*)(a_anim);
-		m_transform.resize( anim->get_num_joints() );
 		update_animation( a_anim, 0 );
 	}
