Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 229)
+++ trunk/src/formats/md3_loader.cc	(revision 230)
@@ -328,5 +328,5 @@
 */
 
-void nv::md3_loader::load_tags( std::vector<mat4>& t, const std::string& tag )
+void nv::md3_loader::load_tags( std::vector<transform>& t, const std::string& tag )
 {
 	md3_t* md3 = (md3_t*)m_md3;
@@ -340,9 +340,9 @@
 			if (rname == tag)
 			{
-				vec4 axisx     = vec4( md3_vec3( rtag.axis[0] ), 0.0 );
-				vec4 axisz     = vec4( md3_vec3( rtag.axis[1] ), 0.0 );
-				vec4 axisy     = vec4( md3_vec3( rtag.axis[2] ), 0.0 );
-				vec4 origin    = vec4( md3_vec3( rtag.origin ),  1.0 );
-				t.emplace_back( axisx, axisy, axisz, origin );
+				vec3 axisx  ( md3_vec3( rtag.axis[0] ) );
+				vec3 axisz  ( md3_vec3( rtag.axis[1] ) );
+				vec3 axisy  ( md3_vec3( rtag.axis[2] ) );
+				vec3 origin ( md3_vec3( rtag.origin )  );
+				t.emplace_back( origin, quat( mat3( axisx, axisy, axisz ) ) );
 			}
 		}
@@ -406,5 +406,5 @@
 }
 
-mat4 md3_loader::get_tag( sint32 frame, const std::string& name ) const
+transform md3_loader::get_tag( sint32 frame, const std::string& name ) const
 {
 	md3_t* md3 = (md3_t*)m_md3;
@@ -415,12 +415,12 @@
 		if (rname == name)
 		{
-			vec4 axisx     = vec4( md3_vec3( rtag.axis[0] ), 0.0 );
-			vec4 axisz     = vec4( md3_vec3( rtag.axis[1] ), 0.0 );
-			vec4 axisy     = vec4( md3_vec3( rtag.axis[2] ), 0.0 );
-			vec4 origin    = vec4( md3_vec3( rtag.origin ),  1.0 );
-			return glm::mat4( axisx, axisy, axisz, origin );
-		}
-	}
-	return glm::mat4();
+			vec3 axisx ( md3_vec3( rtag.axis[0] ) );
+			vec3 axisz ( md3_vec3( rtag.axis[1] ) );
+			vec3 axisy ( md3_vec3( rtag.axis[2] ) );
+			vec3 origin( md3_vec3( rtag.origin ) );
+			return transform( origin, quat( mat3( axisx, axisy, axisz ) ) );
+		}
+	}
+	return transform();
 }
 
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 229)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 230)
@@ -15,9 +15,7 @@
 using namespace nv;
 
-keyframed_mesh::keyframed_mesh( context* a_context, mesh_data* a_data, program* a_program )
-	: m_context( a_context )
+keyframed_mesh::keyframed_mesh( context* a_context, mesh_data* a_data )
+	: animated_mesh( a_context )
 	, m_data( a_data )
-	, m_program( a_program )
-	, m_va( nullptr )
 	, m_start_frame( false )
 	, m_stop_frame( false )
@@ -38,8 +36,8 @@
 }
 
-mat4 keyframed_mesh::get_tag( const std::string& tag ) const
-{
-	const std::vector< nv::mat4 >& transforms = m_data->get_tag_map().at( tag );
-	return glm::interpolate( transforms[ m_last_frame ], transforms[ m_next_frame ], m_interpolation );
+transform keyframed_mesh::get_tag( const std::string& tag ) const
+{
+	const std::vector< transform >& transforms = m_data->get_tag_map().at( tag );
+	return interpolate( transforms[ m_last_frame ], transforms[ m_next_frame ], m_interpolation );
 }
 
@@ -101,8 +99,7 @@
 }
 
-void nv::keyframed_mesh::draw( render_state& rstate )
-{
-	m_program->set_opt_uniform( "nv_interpolate", m_interpolation );
-	m_context->draw( nv::TRIANGLES, rstate, m_program, m_va, m_data->get_index_count() );
+void nv::keyframed_mesh::update( program* a_program )
+{
+	a_program->set_opt_uniform( "nv_interpolate", m_interpolation );
 }
 
@@ -112,6 +109,12 @@
 }
 
+void nv::keyframed_mesh::run_animation( animation_entry* a_anim )
+{
+	keyframed_animation_entry * anim = down_cast<keyframed_animation_entry>(a_anim);
+	setup_animation( anim->m_start, anim->m_frames, anim->m_fps, anim->m_looping );
+}
+
 keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, mesh_data* a_data, program* a_program )
-	: keyframed_mesh( a_context, a_data, a_program )
+	: keyframed_mesh( a_context, a_data )
 	, m_loc_next_position( 0 )
 	, m_loc_next_normal( 0 )
@@ -120,6 +123,6 @@
 {
 	nv::vertex_buffer* vb;
-	m_loc_next_position = m_program->get_attribute( "nv_next_position" )->get_location();
-	m_loc_next_normal   = m_program->get_attribute( "nv_next_normal" )->get_location();
+	m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
+	m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
 
 	vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ) * m_data->get_frame_count(), (void*)m_data->get_positions().data() );
@@ -137,6 +140,8 @@
 }
 
-void nv::keyframed_mesh_gpu::draw( render_state& rstate )
-{
+void nv::keyframed_mesh_gpu::update( uint32 ms )
+{
+	keyframed_mesh::update( ms );
+
 	size_t vtx_count = m_data->get_vertex_count();
 	if ( m_gpu_last_frame != m_last_frame )
@@ -152,10 +157,9 @@
 		m_gpu_next_frame = m_next_frame;
 	}
-	keyframed_mesh::draw( rstate );
-}
-
-
-nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, mesh_data* a_data, program* a_program )
-	: keyframed_mesh( a_context, a_data, a_program )
+}
+
+
+nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, mesh_data* a_data )
+	: keyframed_mesh( a_context, a_data )
 {
 	m_vb_position = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ), (void*)m_data->get_position_frame(0) );
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 229)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 230)
@@ -11,8 +11,6 @@
 
 
-nv::skeletal_mesh::skeletal_mesh( context* a_context, program* a_program, md5_loader* a_loader )
-	: m_context( a_context )
-	, m_program( a_program )
-	, m_va( nullptr )
+nv::skeletal_mesh::skeletal_mesh( context* a_context, md5_loader* a_loader )
+	: animated_mesh( a_context )
 	, m_data( a_loader )
 	, m_animation( nullptr )
@@ -38,4 +36,5 @@
 	if ( m_animation ) m_animation->reset_animation();
 	m_animation = a_anim;
+	// TODO : INSTANCE!
 	m_animation->reset_animation();
 }
@@ -64,11 +63,13 @@
 }
 
-void nv::skeletal_mesh::draw( render_state& rstate )
-{
-	m_context->draw( nv::TRIANGLES, rstate, m_program, m_va, m_data->get_index_count(0) );
-}
-
 nv::skeletal_mesh::~skeletal_mesh()
 {
 	delete m_va;
 }
+
+void nv::skeletal_mesh::run_animation( animation_entry* a_anim )
+{
+	skeletal_animation_entry * anim = down_cast<skeletal_animation_entry>(a_anim);
+	// TODO : INSTANCE!
+	setup_animation( anim->m_animation );
+}
