Index: trunk/src/formats/md2_loader.cc
===================================================================
--- trunk/src/formats/md2_loader.cc	(revision 238)
+++ trunk/src/formats/md2_loader.cc	(revision 239)
@@ -203,5 +203,5 @@
 static bool s_md2_normal_ready = false;
 
-md2_loader::md2_loader() : m_md2( nullptr ), m_size( 0 )
+md2_loader::md2_loader() : m_md2( nullptr )
 {
 	if ( !s_md2_normal_ready )
@@ -230,5 +230,4 @@
 bool md2_loader::load( stream& source )
 {
-	m_size = 0;
 	m_md2 = (void*)(new md2_t);
 	if ( !read_md2( (md2_t*)m_md2, source ) )
@@ -237,143 +236,10 @@
 	}
 	reindex();
-	m_size = m_new_indexes.size();
 	return true;
 }
 
-mesh_data_old* nv::md2_loader::release_mesh_data()
-{
-	mesh_data_creator m;
-
-	load_positions( m.get_positions() );
-	load_normals( m.get_normals() );
-	load_texcoords( m.get_texcoords() );
-	load_indicies( m.get_indices() );
-
-	m_size = m.get_indices().size();
-	return m.release();
-}
-
-mesh_data_old* nv::md2_loader::get_frame( sint32 frame )
-{
-	mesh_data_creator m;
-
-	load_positions( m.get_positions(), frame );
-	load_normals( m.get_normals(), frame );
-	load_texcoords( m.get_texcoords() );
-	load_indicies( m.get_indices() );
-
-	m_size = m.get_indices().size();
-	return m.release();
-}
-
-
-/*
-mesh* nv::md2_loader::release_mesh()
-{
-	return get_frame( 0 );
-}
-
-mesh* nv::md2_loader::get_frame( sint32 frame )
-{
-	md2_t* md2 = (md2_t*)m_md2;
-	if ( md2 == nullptr || frame >= md2->header.num_frames ) return nullptr;
-	mesh* m = new mesh();
-
-	vertex_attribute< vec3 >*   position = m->add_attribute<vec3>("nv_position");
-	vertex_attribute< vec3 >*   normal   = m->add_attribute<vec3>("nv_normal");
-	vertex_attribute< vec2 >*   texcoord = m->add_attribute<vec2>("nv_texcoord");
-	vertex_attribute< uint32 >* indices  = m->add_indices<uint32>();
-
-	load_positions( position->get(), frame );
-	load_normals( normal->get(), frame );
-
-	load_texcoords( texcoord->get() );
-	load_indicies( indices->get() );
-
-	m_size = indices->get().size();
-	return m;
-}
-*/
-
 size_t md2_loader::get_max_frames() const
 {
 	return static_cast< size_t >( ((md2_t*)m_md2)->header.num_frames );
-}
-
-void md2_loader::load_positions( std::vector<vec3>& p, sint32 frame /*=-1*/ )
-{
-	md2_t* md2 = (md2_t*)m_md2;
-	size_t num_frames = static_cast< size_t >( md2->header.num_frames );
-	size_t num_verts  =	m_new_vindexes.size();
-	p.clear();
-	size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t >( frame ) );
-	size_t frame_count   = ( frame == -1 ? num_frames : 1 );
-
-	p.reserve( num_verts * frame_count );
-
-	while ( frame_count > 0 )
-	{
-		const md2_frame_t& cframe = md2->frames[current_frame];
-		NV_LOG( LOG_INFO, "FrameID = " << cframe.name );
-
-		vec3 scale     = md2_vec3( cframe.scale );
-		vec3 translate = md2_vec3( cframe.translate );
-
-		for (size_t i = 0; i < num_verts; ++i )
-		{
-			const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
-			p.push_back( vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate );
-		}
-		++current_frame;
-		--frame_count;
-	}
-}
-
-void md2_loader::load_normals( std::vector<vec3>& n, sint32 frame /*=-1*/ )
-{
-	md2_t* md2 = (md2_t*)m_md2;
-	size_t num_frames = static_cast< size_t >( md2->header.num_frames );
-	size_t num_verts  =	m_new_vindexes.size();
-	n.clear();
-	size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t>( frame ) );
-	size_t frame_count   = ( frame == -1 ? num_frames : 1 );
-
-	n.reserve( num_verts * frame_count );
-
-	while ( frame_count > 0 )
-	{
-		const md2_frame_t& cframe = md2->frames[current_frame];
-
-		for (size_t i = 0; i < num_verts; ++i )
-		{
-			const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
-			n.push_back( s_md2_normal_cache[ v.n ] );
-		}
-		++current_frame;
-		--frame_count;
-	}
-}
-
-void md2_loader::load_texcoords( std::vector<vec2>& t )
-{
-	md2_t* md2 = (md2_t*)m_md2;
-	size_t num_verts  = m_new_vindexes.size();
-
-	t.clear();
-	t.reserve( num_verts );
-
-	vec2 scale( 1.0f / (float) md2->header.skinwidth, 1.0f / (float) md2->header.skinheight );
-
-	for (size_t i = 0; i < num_verts; ++i )
-	{
-		const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
-		t.push_back( scale * vec2( st.s, st.t ) );
-	}
-
-}
-
-void md2_loader::load_indicies( std::vector<uint32>& idx )
-{
-	idx.assign( m_new_indexes.begin(), m_new_indexes.end() );
 }
 
@@ -433,2 +299,75 @@
 	NV_LOG( LOG_INFO, "Reuse count      = " << stats_reuse );
 }
+
+
+struct vtx_md2_pn
+{
+	nv::vec3 position;
+	nv::vec3 normal;
+};
+
+struct vtx_md2_t
+{
+	nv::vec2 texcoord;
+};
+
+
+mesh_data* nv::md2_loader::release_mesh_data()
+{
+	return release_mesh_data( -1 );
+}
+
+mesh_data* nv::md2_loader::release_mesh_data( sint32 frame )
+{
+	md2_t* md2 = (md2_t*)m_md2;
+	size_t num_frames = static_cast< size_t >( md2->header.num_frames );
+	size_t num_verts  =	m_new_vindexes.size();
+	size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t >( frame ) );
+	size_t frame_count   = ( frame == -1 ? num_frames : 1 );
+
+	mesh_raw_channel* mc_pn = mesh_raw_channel::create< vtx_md2_pn >( num_verts * frame_count );
+	vtx_md2_pn* vtx_pn = (vtx_md2_pn*)mc_pn->data;
+
+	uint32 index = 0;
+	while ( frame_count > 0 )
+	{
+		const md2_frame_t& cframe = md2->frames[current_frame];
+		NV_LOG( LOG_INFO, "FrameID = " << cframe.name );
+
+		vec3 scale     = md2_vec3( cframe.scale );
+		vec3 translate = md2_vec3( cframe.translate );
+
+		for (size_t i = 0; i < num_verts; ++i )
+		{
+			const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
+			vtx_pn[index].position = vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate;
+			vtx_pn[index].normal   = s_md2_normal_cache[ v.n ];
+			index++;
+		}
+		++current_frame;
+		--frame_count;
+	}
+
+	mesh_raw_channel* mc_t = mesh_raw_channel::create< vtx_md2_t >( num_verts );
+	vtx_md2_t* vtx_t = (vtx_md2_t*)mc_t->data;
+
+	vec2 scale( 1.0f / (float) md2->header.skinwidth, 1.0f / (float) md2->header.skinheight );
+	for (size_t i = 0; i < num_verts; ++i )
+	{
+		const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
+		vtx_t[i].texcoord = scale * vec2( st.s, st.t );
+	}
+
+	mesh_raw_index_channel* ic = mesh_raw_index_channel::create< uint16 >( m_new_indexes.size() );
+	if ( m_new_indexes.size() > 0 )
+	{
+		uint16* icp = (uint16*)ic->data;
+		std::copy_n( m_new_indexes.data(), m_new_indexes.size(), icp );
+	}
+
+	mesh_data* result = new mesh_data();
+	result->add_channel( mc_pn );
+	result->add_channel( mc_t );
+	result->set_index_channel( ic );
+	return result;
+}
Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 238)
+++ trunk/src/formats/md3_loader.cc	(revision 239)
@@ -234,5 +234,5 @@
 
 md3_loader::md3_loader()
-	: m_md3( nullptr ), m_size( 0 )
+	: m_md3( nullptr )
 {
 	if ( !s_normal_ready )
@@ -276,5 +276,4 @@
 {
 	m_tags.clear();
-	m_size = 0;
 
 	m_md3 = (void*)(new md3_t);
@@ -285,46 +284,4 @@
 	return true;
 }
-
-/*
-mesh* nv::md3_loader::release_mesh()
-{
-	return get_frame( 0 );
-}
-
-mesh* nv::md3_loader::get_frame( sint32 frame )
-{
-	mesh* m = new mesh();
-	md3_t* md3 = (md3_t*)m_md3;
-
-	NV_LOG( LOG_INFO, "Tags:" );
-	for ( sint32 i = 0; i < md3->header.num_tags; ++i )
-	{
-		const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * frame];
-
-		md3_tag& tag   = m_tags[ (char*)(rtag.name) ];
-		tag.name       = (char*)(rtag.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 );
-		tag.transform  = glm::mat4( axisx, axisy, axisz, origin );
-		NV_LOG( LOG_INFO, "Tag " << tag.name << " found" );
-	}
-
-	vertex_attribute< vec3 >* position = m->add_attribute<vec3>("nv_position");
-	vertex_attribute< vec3 >* normal   = m->add_attribute<vec3>("nv_normal");
-	vertex_attribute< vec2 >* texcoord = m->add_attribute<vec2>("nv_texcoord");
-	vertex_attribute< uint32 >* indices  = m->add_indices<uint32>();
-
-	load_positions( position->get(), frame );
-	load_normals( normal->get(), frame );
-
-	load_texcoords( texcoord->get() );
-	load_indicies( indices->get() );
-
-	m_size = indices->get().size();
-	return m;
-}
-*/
 
 void nv::md3_loader::load_tags( std::vector<transform>& t, const std::string& tag )
@@ -351,95 +308,32 @@
 }
 
-mesh_data_old* nv::md3_loader::release_mesh_data()
-{
-	mesh_data_creator m;
-
-	load_positions( m.get_positions() );
-	load_normals( m.get_normals() );
-	load_texcoords( m.get_texcoords() );
-	load_indicies( m.get_indices() );
-	
-	std::vector< std::string > names;
-	load_tag_names( names );
-
-	for ( auto& name : names )
-	{
-		load_tags( m.get_tag_map()[ name ], name );
-	}
-
-	return m.release();
-}
-
-mesh_data_old* nv::md3_loader::get_frame( sint32 frame )
-{
-	mesh_data_creator m;
-
-	load_positions( m.get_positions(), frame );
-	load_normals( m.get_normals(), frame );
-	load_texcoords( m.get_texcoords() );
-	load_indicies( m.get_indices() );
-
-	std::vector< std::string > names;
-	load_tag_names( names );
-
-	for ( auto& name : names )
-	{
-		load_tags( m.get_tag_map()[ name ], name );
-	}
-	return m.release();
-}
-
-size_t md3_loader::get_max_frames() const
-{
-	return static_cast< size_t >( ((md3_t*)m_md3)->header.num_frames );
-}
-
-void md3_loader::load_tag_names( std::vector< std::string >& tags )
-{
-	tags.clear();
-	md3_t* md3 = (md3_t*)m_md3;
-	for ( sint32 i = 0; i < md3->header.num_tags; ++i )
-	{
-		const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags];
-		tags.push_back( (char*)(rtag.name) );
-	}
-}
-
-transform md3_loader::get_tag( sint32 frame, const std::string& name ) const
-{
-	md3_t* md3 = (md3_t*)m_md3;
-	for ( sint32 i = 0; i < md3->header.num_tags; ++i )
-	{
-		const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * frame];
-		std::string rname((char*)(rtag.name));
-		if (rname == name)
-		{
-			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();
-}
-
-const md3_tag* md3_loader::get_tag( const std::string& name ) const
-{
-	auto it = m_tags.find( name );
-	if ( it == m_tags.end() ) return nullptr;
-	return &(it->second);
-}
-
-void md3_loader::load_positions( std::vector<vec3>& p, sint32 frame /*=-1*/ )
+struct vtx_md3_pn
+{
+	nv::vec3 position;
+	nv::vec3 normal;
+};
+
+struct vtx_md3_t
+{
+	nv::vec2 texcoord;
+};
+
+mesh_data* nv::md3_loader::release_mesh_data()
+{
+	return release_mesh_data( -1 );
+}
+
+mesh_data* nv::md3_loader::release_mesh_data( sint32 frame )
 {
 	md3_t* md3 = (md3_t*)m_md3;
 	sint32 num_surfaces = md3->header.num_surfaces;
-	p.clear();
+	sint32 num_verts    = md3->vertices_per_frame;
 	sint32 current_frame = ( frame == -1 ? 0 : frame );
 	sint32 frame_count   = ( frame == -1 ? md3->header.num_frames : 1 );
 
-	p.reserve( static_cast< size_t >( md3->vertices_per_frame * frame_count ) );
-
+	mesh_raw_channel* mc_pn = mesh_raw_channel::create< vtx_md3_pn >( num_verts * frame_count );
+	vtx_md3_pn* vtx_pn = (vtx_md3_pn*)mc_pn->data;
+
+	uint32 index = 0;
 	while ( frame_count > 0 )
 	{
@@ -453,80 +347,73 @@
 			{
 				md3_vertex_t& v = surface.vertices[j];
-				p.push_back( vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE ) );
+				vtx_pn[index].position = vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE );
+				vtx_pn[index].normal   = s_normal_cache[ v.normal ];
+				index++;
 			}
+
 		}
 		++current_frame;
 		--frame_count;
 	}
-}
-
-void md3_loader::load_normals( std::vector<vec3>& n, sint32 frame /*=-1*/ )
-{
-	md3_t* md3 = (md3_t*)m_md3;
-	sint32 num_surfaces = md3->header.num_surfaces;
-	n.clear();
-	sint32 current_frame = ( frame == -1 ? 0 : frame );
-	sint32 frame_count   = ( frame == -1 ? md3->header.num_frames : 1 );
-
-	n.reserve( static_cast< size_t >( md3->vertices_per_frame * frame_count ) );
-
-	while ( frame_count > 0 )
-	{
-		for ( sint32 i = 0; i < num_surfaces; ++i )
-		{
-			md3_surface_t& surface = md3->surfaces[i];
-			sint32         vcount  = surface.header.num_verts;
-			sint32         offset  = vcount * current_frame;
-			sint32         limit   = vcount + offset;
-			for (sint32 j = offset; j < limit; ++j )
-			{
-				n.push_back( s_normal_cache[ surface.vertices[j].normal ] );
-			}
-		}
-		++current_frame;
-		--frame_count;
-	}
-}
-
-void md3_loader::load_texcoords( std::vector<vec2>& t )
-{
-	md3_t* md3 = (md3_t*)m_md3;
-	sint32 num_surfaces = md3->header.num_surfaces;
-	t.clear();
+
+	index = 0;
+	mesh_raw_channel* mc_t = mesh_raw_channel::create< vtx_md3_t >( num_verts );
+	vtx_md3_t* vtx_t = (vtx_md3_t*)mc_t->data;
 	for ( sint32 i = 0; i < num_surfaces; ++i )
 	{
 		const md3_surface_t& surface = md3->surfaces[i];
 		const uint32         vcount  = static_cast< uint32 >( surface.header.num_verts );
-		t.reserve( t.size() + vcount );
 		for (uint32 j = 0; j < vcount; ++j )
 		{
-			t.push_back( md3_texcoord( surface.st[j] ) );
+			vtx_t[index++].texcoord = md3_texcoord( surface.st[j] );
 		}
 	}
-}
-
-void md3_loader::load_indicies( std::vector<uint32>& idx )
-{
-	md3_t* md3 = (md3_t*)m_md3;
-	sint32 num_surfaces = md3->header.num_surfaces;
-	idx.clear();
+
+	sint32 index_count = 0;
+	for ( sint32 i = 0; i < num_surfaces; ++i )
+	{
+		index_count += md3->surfaces[i].header.num_triangles * 3;
+	}
+
+	index = 0;
 	sint32 index_base = 0;
+	mesh_raw_index_channel* ic = mesh_raw_index_channel::create< uint16 >( index_count );
+	uint16* icp = (uint16*)ic->data;
 	for ( sint32 i = 0; i < num_surfaces; ++i )
 	{
 		const md3_surface_t& surface = md3->surfaces[i];
 		const size_t         tcount  = static_cast< size_t >( surface.header.num_triangles );
-
-		idx.reserve( idx.size() + tcount * 3 );
 		for (size_t j = 0; j < tcount; ++j )
 		{
 			const md3_triangle_t& t = surface.triangles[j];
-			idx.push_back( static_cast< uint32 >( index_base + t.indexes[0] ) );
-			idx.push_back( static_cast< uint32 >( index_base + t.indexes[1] ) );
-			idx.push_back( static_cast< uint32 >( index_base + t.indexes[2] ) );
+			icp[index++] = static_cast< uint16 >( index_base + t.indexes[0] );
+			icp[index++] = static_cast< uint16 >( index_base + t.indexes[1] );
+			icp[index++] = static_cast< uint16 >( index_base + t.indexes[2] );
 		}
-
 		index_base += surface.header.num_verts;
 	}
 
-}
-
+	mesh_data* result = new mesh_data();
+	result->add_channel( mc_pn );
+	result->add_channel( mc_t );
+	result->set_index_channel( ic );
+	return result;
+}
+
+tag_map* nv::md3_loader::create_tag_map()
+{
+	md3_t* md3 = (md3_t*)m_md3;
+	tag_map* result = new tag_map();
+	for ( sint32 i = 0; i < md3->header.num_tags; ++i )
+	{
+		const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags];
+		std::string name( (char*)(rtag.name) );
+		load_tags( result->get_map()[ name ], name );
+	}
+	return result;
+}
+
+size_t md3_loader::get_max_frames() const
+{
+	return static_cast< size_t >( ((md3_t*)m_md3)->header.num_frames );
+}
Index: trunk/src/formats/md5_loader.cc
===================================================================
--- trunk/src/formats/md5_loader.cc	(revision 238)
+++ trunk/src/formats/md5_loader.cc	(revision 239)
@@ -90,5 +90,6 @@
 		else if ( command == "mesh" )
 		{
-			md5_mesh* mesh = new md5_mesh;
+			md5_mesh_data* mesh = new md5_mesh_data();
+
 			int num_verts, num_tris, num_weights;
 
@@ -99,6 +100,6 @@
 				if ( command == "shader" )
 				{
-					sstream >> mesh->shader;
-					remove_quotes( mesh->shader );
+					sstream >> mesh->m_shader;
+					remove_quotes( mesh->m_shader );
 					// texturePath.replace_extension( ".tga" );
 					next_line( sstream );
@@ -107,24 +108,29 @@
 				{
 					sstream >> num_verts; 
+
+					{
+						mesh_raw_channel* ch_pnt = mesh_raw_channel::create<md5_vtx_pnt>( num_verts );
+						mesh_raw_channel* ch_t   = mesh_raw_channel::create<md5_vtx_t>( num_verts );
+						mesh->m_pntdata          = (md5_vtx_pnt*)ch_pnt->data;
+						mesh->m_tdata            = (md5_vtx_t*)ch_t->data;
+						mesh->add_channel( ch_pnt );
+						mesh->add_channel( ch_t );
+					}
+					mesh->m_vtx_data.resize( num_verts );
+
 					next_line( sstream );
 					std::string line;
 					for ( int i = 0; i < num_verts; ++i )
 					{
-						md5_vertex vert;
+						md5_vtx_data& vdata = mesh->m_vtx_data[i];
+						size_t weight_count;
+						size_t start_weight;
+						vec2 texcoord;
 
 						std::getline( sstream, line );
-						sscanf( line.c_str(), "%*s %*u ( %f %f ) %u %u", &(vert.texcoord.x), &(vert.texcoord.y), &(vert.start_weight), &(vert.weight_count) );
-
-// 						std::string ignore;
-// 						discard( sstream, "vert" );
-// 						sstream >> ignore;
-// 						discard( sstream, "(" );
-// 						sstream >> vert.texcoord.x >> vert.texcoord.y;
-// 						discard( sstream, ")" );
-// 						sstream >> vert.start_weight >> vert.weight_count;
-// 						next_line( sstream );
-
-						mesh->verts.push_back(vert);
-						mesh->texcoord_buffer.push_back( vert.texcoord );
+						sscanf( line.c_str(), "%*s %*u ( %f %f ) %u %u", &(texcoord.x), &(texcoord.y), &(start_weight), &(weight_count) );
+						vdata.start_weight = start_weight;
+						vdata.weight_count = weight_count;
+						mesh->m_tdata[i].texcoord = texcoord;
 					}  
 				}
@@ -132,22 +138,25 @@
 				{
 					sstream >> num_tris;
+
+					mesh_raw_index_channel* ch_i = mesh_raw_index_channel::create<uint32>( num_tris * 3 );
+					uint32* vtx_i                = (uint32*)ch_i->data;
+					mesh->m_idata                = vtx_i;
+					uint32 idx = 0;
+					mesh->set_index_channel( ch_i );
+
 					next_line( sstream );
 					std::string line;
 					for ( int i = 0; i < num_tris; ++i )
 					{
-						md5_triangle tri;
+						size_t ti0;
+						size_t ti1;
+						size_t ti2;
 
 						std::getline( sstream, line );
-						sscanf( line.c_str(), "%*s %*u %u %u %u )", &(tri.indices[0]), &(tri.indices[1]), &(tri.indices[2]));
-
-// 						std::string ignore;
-// 						discard( sstream, "tri" );
-// 						sstream >> ignore >> tri.indices[0] >> tri.indices[1] >> tri.indices[2];
-// 						next_line( sstream );
-
-						mesh->tris.push_back( tri );
-						mesh->index_buffer.push_back( (uint32)tri.indices[0] );
-						mesh->index_buffer.push_back( (uint32)tri.indices[1] );
-						mesh->index_buffer.push_back( (uint32)tri.indices[2] );
+						sscanf( line.c_str(), "%*s %*u %u %u %u )", &(ti0), &(ti1), &(ti2));
+
+						vtx_i[idx++] = (uint32)ti0;
+						vtx_i[idx++] = (uint32)ti1;
+						vtx_i[idx++] = (uint32)ti2;
 					}              
 				}
@@ -155,5 +164,5 @@
 				{
 					sstream >> num_weights;
-					mesh->weights.reserve( num_weights );
+					mesh->m_weights.reserve( num_weights );
 					next_line( sstream );
 					std::string line;
@@ -164,13 +173,5 @@
 						std::getline( sstream, line );
 						sscanf( line.c_str(), "%*s %*u %u %f ( %f %f %f )", &(weight.joint_id), &(weight.bias), &(weight.pos.x), &(weight.pos.y), &(weight.pos.z));
-
-//  						std::string ignore;
-//  						discard( sstream, "weight" );
-//  						sstream >> ignore >> weight.joint_id >> weight.bias;
-//  						discard( sstream, "(" );
-//  						sstream >> weight.pos.x >> weight.pos.y >> weight.pos.z;
-//  						discard( sstream, ")" );
-//  						next_line( sstream );
- 						mesh->weights.push_back(weight);
+ 						mesh->m_weights.push_back(weight);
 					}
 				}
@@ -184,5 +185,4 @@
 
 			prepare_mesh( mesh );
-			prepare_normals( mesh );
 
 			m_meshes.push_back(mesh);
@@ -196,44 +196,40 @@
 }
 
-bool md5_loader::prepare_mesh( md5_mesh* mesh )
-{
-	mesh->position_buffer.clear();
-	mesh->texcoord_buffer.clear();
-
-	for ( uint32 i = 0; i < mesh->verts.size(); ++i )
-	{
-		md5_vertex& vert = mesh->verts[i];
-
-		vert.position = glm::vec3(0);
-		vert.normal   = glm::vec3(0);
-		vert.tangent  = glm::vec3(0);
-
-		for ( size_t j = 0; j < vert.weight_count; ++j )
-		{
-			md5_weight& weight = mesh->weights[vert.start_weight + j];
+bool md5_loader::prepare_mesh( md5_mesh_data* mdata )
+{
+	uint32 vtx_count = mdata->m_vtx_data.size();
+	md5_vtx_pnt* vtcs = mdata->m_pntdata;
+
+	for ( uint32 i = 0; i < vtx_count; ++i )
+	{
+		md5_vtx_data& vdata = mdata->m_vtx_data[i];
+		md5_vtx_pnt& vtc = vtcs[i];
+
+		vtc.position = glm::vec3(0);
+		vtc.normal   = glm::vec3(0);
+		vtc.tangent  = glm::vec3(0);
+
+		for ( size_t j = 0; j < vdata.weight_count; ++j )
+		{
+			md5_weight& weight = mdata->m_weights[vdata.start_weight + j];
 			md5_joint&  joint  = m_joints[weight.joint_id];
 
 			glm::vec3 rot_pos = joint.orient * weight.pos;
 
-			vert.position += ( joint.pos + rot_pos ) * weight.bias;
-		}
-
-		mesh->position_buffer.push_back(vert.position);
-		mesh->texcoord_buffer.push_back(vert.texcoord);
-	}
-
-	return true;
-}
-
-bool md5_loader::prepare_normals( md5_mesh* mesh )
-{
-	mesh->normal_buffer.clear();
-
-	for ( unsigned int i = 0; i < mesh->tris.size(); ++i )
-	{
-		const md5_triangle& tri = mesh->tris[i];
-		glm::vec3 v1 = mesh->verts[ tri.indices[0] ].position;
-		glm::vec3 v2 = mesh->verts[ tri.indices[1] ].position;
-		glm::vec3 v3 = mesh->verts[ tri.indices[2] ].position;
+			vtc.position += ( joint.pos + rot_pos ) * weight.bias;
+		}
+	}
+
+	// Prepare normals
+	uint32 tri_count = mdata->get_count() / 3;
+	for ( unsigned int i = 0; i < tri_count; ++i )
+	{
+		uint32 ti0 = mdata->m_idata[ i * 3 ];
+		uint32 ti1 = mdata->m_idata[ i * 3 + 1 ];
+		uint32 ti2 = mdata->m_idata[ i * 3 + 2 ];
+ 
+		glm::vec3 v1 = vtcs[ ti0 ].position;
+		glm::vec3 v2 = vtcs[ ti1 ].position;
+		glm::vec3 v3 = vtcs[ ti2 ].position;
 		glm::vec3 xyz1 = v3 - v1;
 		glm::vec3 xyz2 = v2 - v1;
@@ -241,11 +237,11 @@
 		glm::vec3 normal = glm::cross( xyz1, xyz2 );
 
-		mesh->verts[ tri.indices[0] ].normal += normal;
-		mesh->verts[ tri.indices[1] ].normal += normal;
-		mesh->verts[ tri.indices[2] ].normal += normal;
-
-		const vec2& w1 = mesh->verts[ tri.indices[0] ].texcoord;
-		const vec2& w2 = mesh->verts[ tri.indices[1] ].texcoord;
-		const vec2& w3 = mesh->verts[ tri.indices[2] ].texcoord;
+		vtcs[ ti0 ].normal += normal;
+		vtcs[ ti1 ].normal += normal;
+		vtcs[ ti2 ].normal += normal;
+
+		const vec2& w1 = mdata->m_tdata[ ti0 ].texcoord;
+		const vec2& w2 = mdata->m_tdata[ ti1 ].texcoord;
+		const vec2& w3 = mdata->m_tdata[ ti2 ].texcoord;
 
 		vec2 st1 = w3 - w1;
@@ -256,28 +252,28 @@
 		vec3 tangent = (( xyz1 * st2.y ) - ( xyz2 * st1.y )) * coef;
 
-		mesh->verts[ tri.indices[0] ].tangent += tangent;
-		mesh->verts[ tri.indices[1] ].tangent += tangent;
-		mesh->verts[ tri.indices[2] ].tangent += tangent;
-	}
-
-	for ( size_t i = 0; i < mesh->verts.size(); ++i )
-	{
-		md5_vertex& vert = mesh->verts[i];
-
-		glm::vec3 normal  = glm::normalize( vert.normal );
-		glm::vec3 tangent = glm::normalize( vert.tangent );
-		mesh->normal_buffer.push_back( normal );
-		mesh->tangent_buffer.push_back( tangent );
-
-		vert.normal  = glm::vec3(0);
-		vert.tangent = glm::vec3(0);
-
-		for ( size_t j = 0; j < vert.weight_count; ++j )
-		{
-			const md5_weight& weight = mesh->weights[vert.start_weight + j];
-			const md5_joint&  joint  = m_joints[weight.joint_id];
-			vert.normal  += ( normal  * joint.orient ) * weight.bias;
-			vert.tangent += ( tangent * joint.orient ) * weight.bias;
-		}
+		vtcs[ ti0 ].tangent += tangent;
+		vtcs[ ti1 ].tangent += tangent;
+		vtcs[ ti2 ].tangent += tangent;
+	}
+
+	for ( size_t i = 0; i < vtx_count; ++i )
+	{
+		md5_vtx_data& vdata = mdata->m_vtx_data[i];
+
+		glm::vec3 normal  = glm::normalize( vtcs[i].normal );
+		glm::vec3 tangent = glm::normalize( vtcs[i].tangent );
+		vtcs[i].normal   = normal;
+		vtcs[i].tangent  = tangent;
+
+ 		vdata.normal  = glm::vec3(0);
+ 		vdata.tangent = glm::vec3(0);
+ 
+ 		for ( size_t j = 0; j < vdata.weight_count; ++j )
+ 		{
+ 			const md5_weight& weight = mdata->m_weights[vdata.start_weight + j];
+ 			const md5_joint&  joint  = m_joints[weight.joint_id];
+ 			vdata.normal  += ( normal  * joint.orient ) * weight.bias;
+ 			vdata.tangent += ( tangent * joint.orient ) * weight.bias;
+ 		}
 	}
 
@@ -285,36 +281,4 @@
 }
 
-mesh_data_old* nv::md5_loader::release_submesh_data( uint32 mesh_id )
-{
-	mesh_data_creator m;
-	m.get_positions().assign( m_meshes[mesh_id]->position_buffer.begin(), m_meshes[mesh_id]->position_buffer.begin() );
-	m.get_normals()  .assign( m_meshes[mesh_id]->normal_buffer.begin(),   m_meshes[mesh_id]->normal_buffer.begin() );
-	m.get_tangents() .assign( m_meshes[mesh_id]->tangent_buffer.begin(),  m_meshes[mesh_id]->tangent_buffer.begin() );
-	m.get_texcoords().assign( m_meshes[mesh_id]->texcoord_buffer.begin(), m_meshes[mesh_id]->texcoord_buffer.begin() );
-	m.get_indices()  .assign( m_meshes[mesh_id]->index_buffer.begin(),    m_meshes[mesh_id]->index_buffer.begin() );
-
-	return m.release();
-}
-
-/*
-mesh* md5_loader::release_mesh()
-{
-	mesh* m = new mesh();
-	auto position = m->add_attribute< vec3 >( "nv_position" );
-	auto normal   = m->add_attribute< vec3 >( "nv_normal" );
-	auto texcoord = m->add_attribute< vec2 >( "nv_texcoord" );
-	auto tangent  = m->add_attribute< vec3 >( "nv_tangent" );
-	auto indices  = m->add_indices< uint32 >();
-
-	position->get().assign( m_meshes[0].position_buffer.begin(), m_meshes[0].position_buffer.end() );
-	normal  ->get().assign( m_meshes[0].normal_buffer.begin(),   m_meshes[0].normal_buffer.end() );
-	texcoord->get().assign( m_meshes[0].texcoord_buffer.begin(), m_meshes[0].texcoord_buffer.end() );
-	tangent ->get().assign( m_meshes[0].tangent_buffer.begin(),  m_meshes[0].tangent_buffer.end() );
-	indices ->get().assign( m_meshes[0].index_buffer.begin(),    m_meshes[0].index_buffer.end() );
-
-	m_size = m_meshes[0].index_buffer.size();
-	return m;
-}
-*/
 
 md5_animation::md5_animation()
@@ -570,44 +534,40 @@
 }
 
-bool md5_loader::prepare_animated_mesh( md5_mesh* mesh, const md5_animation::md5_frame_skeleton& skel )
-{
-	for ( unsigned int i = 0; i < mesh->verts.size(); ++i )
-	{
-		const md5_vertex& vert = mesh->verts[i];
-		glm::vec3& pos     = mesh->position_buffer[i];
-		glm::vec3& normal  = mesh->normal_buffer[i];
-		glm::vec3& tangent = mesh->tangent_buffer[i];
-
-		pos     = glm::vec3(0);
-		normal  = glm::vec3(0);
-		tangent = glm::vec3(0);
+mesh_data* nv::md5_loader::release_mesh_data( uint32 mesh )
+{
+	mesh_data* result = m_meshes[ mesh ];
+	m_meshes[ mesh ] = nullptr;
+	return result;
+}
+
+void nv::md5_mesh_data::apply( const md5_animation& animation )
+{
+	const md5_animation::md5_frame_skeleton& skeleton = animation.get_skeleton();
+
+	for ( unsigned int i = 0; i < m_vtx_data.size(); ++i )
+	{
+		const md5_vtx_data& vert = m_vtx_data[i];
+		md5_vtx_pnt& result = m_pntdata[i];
+
+		result.position = glm::vec3(0);
+		result.normal   = glm::vec3(0);
+		result.tangent  = glm::vec3(0);
 
 		for ( size_t j = 0; j < vert.weight_count; ++j )
 		{
-			const md5_weight& weight = mesh->weights[vert.start_weight + j];
-			const md5_animation::md5_skeleton_joint& joint = skel.joints[weight.joint_id];
+			const md5_weight& weight = m_weights[vert.start_weight + j];
+			const md5_animation::md5_skeleton_joint& joint = skeleton.joints[weight.joint_id];
 
 			glm::vec3 rot_pos = joint.orient * weight.pos;
-			pos += ( joint.pos + rot_pos ) * weight.bias;
-
-			normal  += ( joint.orient * vert.normal  ) * weight.bias;
-			tangent += ( joint.orient * vert.tangent ) * weight.bias;
-		}
-	}
-	return true;
-}
-
-void md5_loader::apply( const md5_animation& animation )
-{
-	const md5_animation::md5_frame_skeleton& skeleton = animation.get_skeleton();
-
-	for ( unsigned int i = 0; i < m_meshes.size(); ++i )
-	{
-		prepare_animated_mesh( m_meshes[i], skeleton );
-	}
-}
-
-size_t nv::md5_loader::get_size()
-{
-	return m_size;
-}
+			result.position += ( joint.pos + rot_pos ) * weight.bias;
+
+			result.normal  += ( joint.orient * vert.normal  ) * weight.bias;
+			result.tangent += ( joint.orient * vert.tangent ) * weight.bias;
+		}
+	}
+}
+
+nv::md5_loader::~md5_loader()
+{
+	for ( auto m : m_meshes ) { if (m) delete m; }
+}
Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 238)
+++ trunk/src/formats/obj_loader.cc	(revision 239)
@@ -56,6 +56,6 @@
 	bool read_stream( std::istream& stream );
 	virtual size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count ) = 0;
-	virtual size_t raw_size() { return 0; }
-	virtual const uint8* raw_pointer() { return nullptr; }
+	virtual size_t raw_size() const = 0;
+	virtual const uint8* raw_pointer() const = 0;
 	virtual void calculate_tangents() {}
 
@@ -151,138 +151,4 @@
 
 
-struct mesh_obj_reader : public obj_reader
-{
-	mesh_obj_reader( mesh_data_creator* m ) : m_mesh( m ) {}
-	virtual std::size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count );
-	virtual void calculate_tangents();
-
-	mesh_data_creator* m_mesh;
-};
-
-size_t mesh_obj_reader::add_face( uint32* vi, uint32* ti, uint32* ni, size_t count )
-{
-	if ( count < 3 )
-	{
-		// TODO : report error?
-		return 0;
-	}
-
-	// TODO : support if normals not present;
-
-	std::vector< vec3 >& vp = m_mesh->get_positions();
-	std::vector< vec3 >& vn = m_mesh->get_normals();
-	std::vector< vec2 >& vt = m_mesh->get_texcoords();
-
-	std::size_t result = 0;
-
-	// Simple triangulation - obj's shouldn't have more than quads anyway
-	for ( size_t i = 2; i < count; ++i )
-	{
-		result++;
-		vp.push_back( v[ vi[ 0 ] ] );   vt.push_back( t[ ti[ 0 ] ] );   vn.push_back( n[ ni[ 0 ] ] );
-		vp.push_back( v[ vi[ i-1 ] ] ); vt.push_back( t[ ti[ i-1 ] ] ); vn.push_back( n[ ni[ i-1 ] ] );
-		vp.push_back( v[ vi[ i ] ] );   vt.push_back( t[ ti[ i ] ] );   vn.push_back( n[ ni[ i ] ] );
-	}
-
-	return result;
-}
-
-// based on http://www.terathon.com/code/tangent.html
-void mesh_obj_reader::calculate_tangents()
-{
-	const std::vector< vec3 >& vp = m_mesh->get_positions();
-	const std::vector< vec2 >& vt = m_mesh->get_texcoords();
-	const std::vector< vec3 >& vn = m_mesh->get_normals();
-	std::vector< vec3 >& tg = m_mesh->get_tangents();
-
-	size_t count  = vp.size();
-	size_t tcount = count / 3;
-
-	std::vector< vec3 > tan1( count );
-	std::vector< vec3 > tan2( count );
-	tg.resize( count );
-
-	for (size_t a = 0; a < tcount; ++a )
-	{
-		size_t i1 = a * 3;
-		size_t i2 = a * 3 + 1;
-		size_t i3 = a * 3 + 2;
-
-		// TODO: simplify
-
-		const vec3& v1 = vp[i1];
-		const vec3& v2 = vp[i2];
-		const vec3& v3 = vp[i3];
-
-		const vec2& w1 = vt[i1];
-		const vec2& w2 = vt[i2];
-		const vec2& w3 = vt[i3];
-
-		vec3 xyz1 = v2 - v1;
-		vec3 xyz2 = v3 - v1;
-		//vec2 st1  = w2 - w1;
-		//vec2 st2  = w3 - w1;
-
-		float s1 = w2.x - w1.x;
-		float t1 = w2.y - w1.y;
-		float s2 = w3.x - w1.x;
-		float t2 = w3.y - w1.y;
-
-		float stst = s1 * t2 - s2 * t1;
-		float r = 0.0f;
-		if (stst > 0.0f || stst < 0.0f) r = 1.0f / stst;
-
-		vec3 sdir = ( t2 * xyz1 - t1 * xyz2 ) * r;
-		vec3 tdir = ( s1 * xyz2 - s2 * xyz1 ) * r;
-
-		// the += below obviously doesn't make sense in this case, but I'll
-		// leave it here for when I move to indices
-		tan1[i1] += sdir;
-		tan1[i2] += sdir;
-		tan1[i3] += sdir;
-
-		// tan2 not needed anymore??
-		tan2[i1] += tdir;
-		tan2[i2] += tdir;
-		tan2[i3] += tdir;
-	}
-
-	for (std::size_t a = 0; a < count; ++a )
-	{
-		const vec3& n = vn[a];
-		const vec3& t = tan1[a];
-		if ( ! (t.x == 0.0f && t.y == 0.0f && t.z == 0.0f) )
-			tg[a] = vec3( glm::normalize(t - n * glm::dot( n, t )) ); 
-			//tg[a][3] =    (glm::dot(glm::cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
-	}
-
-}
-
-nv::obj_loader::obj_loader( bool tangents )
-	: m_mesh( nullptr ), m_tangents( tangents )
-{
-
-}
-
-nv::obj_loader::~obj_loader()
-{
-	delete m_mesh;
-}
-
-bool nv::obj_loader::load( stream& source )
-{
-	if ( m_mesh != nullptr ) delete m_mesh;
-	mesh_data_creator creator;
-	mesh_obj_reader reader( &creator );
-	std_stream sstream( &source );
-	reader.read_stream( sstream );
-	m_size = reader.size;
-	if ( m_tangents )
-	{
-		reader.calculate_tangents();
-	}
-	m_mesh = creator.release();
-	return true;
-}
 
 struct mesh_data_reader_vt : public obj_reader
@@ -305,6 +171,6 @@
 	}
 	std::vector< obj_vertex_vt > m_data;
-	virtual size_t raw_size() { return m_data.size() * sizeof( obj_vertex_vt ); }
-	virtual const uint8* raw_pointer() { return (const uint8*)m_data.data(); }
+	virtual size_t raw_size() const { return m_data.size() * sizeof( obj_vertex_vt ); }
+	virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
 };
 
@@ -328,6 +194,6 @@
 	}
 	std::vector< obj_vertex_vtn > m_data;
-	virtual size_t raw_size() { return m_data.size() * sizeof( obj_vertex_vtn ); }
-	virtual const uint8* raw_pointer() { return (const uint8*)m_data.data(); }
+	virtual size_t raw_size() const { return m_data.size() * sizeof( obj_vertex_vtn ); }
+	virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
 };
 
@@ -351,6 +217,6 @@
 	}
 	std::vector< obj_vertex_vtnt > m_data;
-	virtual size_t raw_size() { return m_data.size() * sizeof( obj_vertex_vtnt ); }
-	virtual const uint8* raw_pointer() { return (const uint8*)m_data.data(); }
+	virtual size_t raw_size() const { return m_data.size() * sizeof( obj_vertex_vtnt ); }
+	virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
 
 	// based on http://www.terathon.com/code/tangent.html
@@ -423,5 +289,5 @@
 };
 
-nv::wavefront_loader::wavefront_loader( bool normals /*= true*/, bool tangents /*= false */ )
+nv::obj_loader::obj_loader( bool normals /*= true*/, bool tangents /*= false */ )
 	: m_normals( normals ), m_tangents( tangents ), m_mesh( nullptr )
 {
@@ -437,5 +303,5 @@
 }
 
-bool nv::wavefront_loader::load( stream& source )
+bool nv::obj_loader::load( stream& source )
 {
 	if ( m_mesh ) delete m_mesh;
@@ -462,4 +328,5 @@
 	mesh_raw_channel* channel = new mesh_raw_channel();
 	nv::uint8* data = nullptr;
+
 	if ( reader->raw_size() > 0 ) 
 	{
@@ -479,5 +346,5 @@
 }
 
-mesh_data* nv::wavefront_loader::release_mesh_data()
+mesh_data* nv::obj_loader::release_mesh_data()
 {
 	mesh_data* result = m_mesh;
@@ -486,5 +353,5 @@
 }
 
-nv::wavefront_loader::~wavefront_loader()
+nv::obj_loader::~obj_loader()
 {
 	if ( m_mesh ) delete m_mesh;
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 238)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 239)
@@ -15,7 +15,8 @@
 using namespace nv;
 
-keyframed_mesh::keyframed_mesh( context* a_context, mesh_data_old* a_data )
+nv::keyframed_mesh::keyframed_mesh( context* a_context, mesh_data* a_data, tag_map* a_tag_map )
 	: animated_mesh()
-	, m_data( a_data )
+	, m_mesh_data( a_data )
+	, m_tag_map( a_tag_map )
 	, m_start_frame( false )
 	, m_stop_frame( false )
@@ -29,15 +30,21 @@
 {
 	m_va = a_context->get_device()->create_vertex_array();
+
+	m_index_count  = m_mesh_data->get_index_channel()->count;
+	m_vertex_count = m_mesh_data->get_channel_data()[1]->count;
+	m_frame_count  = m_mesh_data->get_channel_data()[0]->count / m_vertex_count;
 }
 
 size_t keyframed_mesh::get_max_frames() const
 {
-	return m_data->get_frame_count();
+	return m_frame_count;
 }
 
 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 );
+	NV_ASSERT( m_tag_map, "TAGMAP FAIL" );
+	const std::vector< transform >* transforms = m_tag_map->get_tag( tag );
+	NV_ASSERT( transforms, "TAG FAIL" );
+	return interpolate( (*transforms)[ m_last_frame ], (*transforms)[ m_next_frame ], m_interpolation );
 }
 
@@ -115,6 +122,6 @@
 }
 
-keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, mesh_data_old* a_data, program* a_program )
-	: keyframed_mesh( a_context, a_data )
+nv::keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, mesh_data* a_data, tag_map* a_tag_map, program* a_program )
+	: keyframed_mesh( a_context, a_data, a_tag_map )
 	, m_loc_next_position( 0 )
 	, m_loc_next_normal( 0 )
@@ -122,21 +129,12 @@
 	, m_gpu_next_frame( 0xFFFFFFFF )
 {
-	nv::vertex_buffer* vb;
 	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();
+	m_va = a_context->get_device()->create_vertex_array( a_data, nv::STATIC_DRAW );
+	vertex_buffer* vb = m_va->find_buffer( nv::POSITION );
+	m_va->add_vertex_buffer( m_loc_next_position, vb, nv::FLOAT, 3, 0,              sizeof( vertex_pn ), false );
+	m_va->add_vertex_buffer( m_loc_next_normal,   vb, nv::FLOAT, 3, sizeof( vec3 ), sizeof( vertex_pn ), false );
+}
 
-	vb = a_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() );
-	m_va->add_vertex_buffer( m_loc_next_position, vb, nv::FLOAT, 3, 0, 0, false );
-	m_va->add_vertex_buffer( nv::POSITION, vb, nv::FLOAT, 3 );
-
-	vb = a_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_normals().data() );
-	m_va->add_vertex_buffer( m_loc_next_normal, vb, nv::FLOAT, 3, 0, 0, false );
-	m_va->add_vertex_buffer( nv::NORMAL, vb, nv::FLOAT, 3 );
-
-	vb = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec2 ), (void*)m_data->get_texcoords().data() );
-	m_va->add_vertex_buffer( nv::slot::TEXCOORD, vb, nv::FLOAT, 2 );
-	nv::index_buffer* ib = a_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_data->get_index_count() * sizeof( nv::uint32 ), (void*)m_data->get_indices().data() );
-	m_va->set_index_buffer( ib, nv::UINT, true );
-}
 
 void nv::keyframed_mesh_gpu::update( uint32 ms )
@@ -144,38 +142,31 @@
 	keyframed_mesh::update( ms );
 
-	size_t vtx_count = m_data->get_vertex_count();
 	if ( m_gpu_last_frame != m_last_frame )
 	{
-		m_va->update_vertex_buffer( slot::POSITION, m_last_frame * vtx_count * sizeof( nv::vec3 ) );
-		m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * vtx_count * sizeof( nv::vec3 ) );
+		m_va->update_vertex_buffer( slot::POSITION, m_last_frame * m_vertex_count * sizeof( vertex_pn ) );
+		m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * m_vertex_count * sizeof( vertex_pn ) + sizeof( vec3 ) );
 		m_gpu_last_frame = m_last_frame;
 	}
 	if ( m_gpu_next_frame != m_next_frame )
 	{
-		m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * vtx_count * sizeof( nv::vec3 ) );
-		m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * vtx_count * sizeof( nv::vec3 ) );
+		m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * sizeof( vertex_pn ) );
+		m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * m_vertex_count * sizeof( vertex_pn ) + sizeof( vec3 ) );
 		m_gpu_next_frame = m_next_frame;
 	}
 }
 
+nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, mesh_data* a_data, tag_map* a_tag_map )
+	: keyframed_mesh( a_context, a_data, a_tag_map )
+{
+	m_vb = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( vertex_pn ), (void*)m_mesh_data->get_channel_data()[0]->data );
+	m_va->add_vertex_buffers( m_vb, m_mesh_data->get_channel_data()[0] );
 
-nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, mesh_data_old* a_data )
-	: keyframed_mesh( a_context, a_data )
-{
-	m_vb_position = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ), (void*)m_data->get_position_frame(0) );
-	m_va->add_vertex_buffer( nv::slot::POSITION, m_vb_position, nv::FLOAT, 3 );
+	nv::vertex_buffer* vb = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( nv::vec2 ), (void*)m_mesh_data->get_channel_data()[1]->data );
+	m_va->add_vertex_buffers( vb, m_mesh_data->get_channel_data()[1] );
 
-	m_vb_normal   = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ), (void*)m_data->get_normal_frame(0) );
-	m_va->add_vertex_buffer( nv::slot::NORMAL, m_vb_normal, nv::FLOAT, 3 );
+	nv::index_buffer* ib = a_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_mesh_data->get_index_channel()->size, (void*)m_mesh_data->get_index_channel()->data );
+	m_va->set_index_buffer( ib, m_mesh_data->get_index_channel()->etype, true );
 
-	nv::vertex_buffer* vb;
-	vb = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec2 ), (void*)m_data->get_texcoords().data() );
-	m_va->add_vertex_buffer( nv::slot::TEXCOORD, vb, nv::FLOAT, 2 );
-
-	nv::index_buffer* ib = a_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_data->get_index_count() * sizeof( nv::uint32 ), (void*)m_data->get_indices().data() );
-	m_va->set_index_buffer( ib, nv::UINT, true );
-
-	m_position.resize( m_data->get_vertex_count() );
-	m_normal.resize( m_data->get_vertex_count() );
+	m_vertex.resize( m_vertex_count );
 }
 
@@ -184,22 +175,16 @@
 	keyframed_mesh::update( ms );
 
-	size_t vtx_count = m_data->get_vertex_count();
-	const vec3* prev_position = m_data->get_position_frame( m_last_frame );
-	const vec3* next_position = m_data->get_position_frame( m_next_frame );
-	const vec3* prev_normal   = m_data->get_normal_frame( m_last_frame );
-	const vec3* next_normal   = m_data->get_normal_frame( m_next_frame );
+	const vertex_pn* data = (const vertex_pn*)(m_mesh_data->get_channel_data()[0]->data);
+	const vertex_pn* prev = data + m_vertex_count * m_last_frame;
+	const vertex_pn* next = data + m_vertex_count * m_next_frame;
 
-	for ( size_t i = 0; i < vtx_count; ++i )
+	for ( size_t i = 0; i < m_vertex_count; ++i )
 	{
-		m_position[i] = glm::mix( prev_position[i], next_position[i], m_interpolation );
-		m_normal[i]   = glm::mix( prev_normal[i],   next_normal[i],   m_interpolation );
+		m_vertex[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
+		m_vertex[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
 	}
 
-	m_vb_position->bind();
-	m_vb_position->update( m_position.data(), 0, vtx_count * sizeof( nv::vec3 ) );
-	m_vb_position->unbind();
-
-	m_vb_normal->bind();
-	m_vb_normal->update( m_normal.data(), 0, vtx_count * sizeof( nv::vec3 ) );
-	m_vb_normal->unbind();
+	m_vb->bind();
+	m_vb->update( m_vertex.data(), 0, m_vertex_count * sizeof( vertex_pn ) );
+	m_vb->unbind();
 }
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 238)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 239)
@@ -11,24 +11,12 @@
 
 
-nv::skeletal_mesh::skeletal_mesh( context* a_context, md5_loader* a_loader )
+nv::skeletal_mesh::skeletal_mesh( context* a_context, md5_mesh_data* a_mesh_data )
 	: animated_mesh()
-	, m_data( a_loader )
+	, m_mesh_data( a_mesh_data )
 	, m_animation( nullptr )
 {
-	nv::uint32 vcount = a_loader->get_vertex_count(0);
-	m_va = a_context->get_device()->create_vertex_array();
+	m_va = a_context->get_device()->create_vertex_array( a_mesh_data, nv::STREAM_DRAW );
+}
 
-	m_vb_position = a_context->get_device()->create_vertex_buffer( nv::STREAM_DRAW, vcount * sizeof( nv::vec3 ), (const void*)a_loader->get_positions(0).data() );
-	m_va->add_vertex_buffer( nv::slot::POSITION, m_vb_position, nv::FLOAT, 3, 0, 0, false );
-	m_vb_normal = a_context->get_device()->create_vertex_buffer( nv::STREAM_DRAW, vcount * sizeof( nv::vec3 ), (const void*)a_loader->get_normals(0).data()  );
-	m_va->add_vertex_buffer( nv::slot::NORMAL,   m_vb_normal, nv::FLOAT, 3, 0, 0, false );
-	m_vb_tangent = a_context->get_device()->create_vertex_buffer( nv::STREAM_DRAW, vcount * sizeof( nv::vec3 ), (const void*)a_loader->get_tangents(0).data() );
-	m_va->add_vertex_buffer( nv::slot::TANGENT,  m_vb_tangent, nv::FLOAT, 3, 0, 0, false );
-
-	nv::vertex_buffer* vb = a_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, vcount * sizeof( nv::vec2 ), (const void*)a_loader->get_texcoords(0).data() );
-	m_va->add_vertex_buffer( nv::slot::TEXCOORD, vb, nv::FLOAT, 2 );
-	nv::index_buffer* ib = a_context->get_device()->create_index_buffer( nv::STATIC_DRAW, a_loader->get_index_count(0) * sizeof( nv::uint32 ), (const void*)a_loader->get_indices(0).data() );
-	m_va->set_index_buffer( ib, nv::UINT, true );
-}
 
 void nv::skeletal_mesh::setup_animation( md5_animation* a_anim )
@@ -45,21 +33,11 @@
 	{
 		m_animation->update( ms * 0.001f );
-		m_data->apply( *m_animation );
+		m_mesh_data->apply( *m_animation );
+		vertex_buffer* vb = m_va->find_buffer( nv::POSITION );
+		const mesh_raw_channel* pch = m_mesh_data->get_channel_data()[0];
+		vb->bind();
+		vb->update( (const void*)pch->data, 0, pch->size );
+		vb->unbind();
 	}
-
-	nv::uint32 usize = m_data->get_vertex_count(0) * sizeof( nv::vec3 );
-	m_vb_position->bind();
-	m_vb_position->update( (const void*)m_data->get_positions(0).data(), 0, usize );
-	m_vb_normal  ->bind();
-	m_vb_normal  ->update( (const void*)m_data->get_normals(0).data(),   0, usize );
-	m_vb_tangent ->bind();
-	m_vb_tangent ->update( (const void*)m_data->get_tangents(0).data(),  0, usize );
-
-	// Technically this is not needed, because the va is just a fake class, 
-	// but if it's real it will be needed?
-// 	m_va->update_vertex_buffer( nv::slot::POSITION, m_vb_position, false );
-// 	m_va->update_vertex_buffer( nv::slot::NORMAL,   m_vb_normal,   false );
-// 	m_va->update_vertex_buffer( nv::slot::TANGENT,  m_vb_tangent,  false );
-	// TODO: answer is - probably not
 }
 
@@ -67,4 +45,5 @@
 {
 	delete m_va;
+	delete m_mesh_data;
 }
 
Index: trunk/src/gui/gui_environment.cc
===================================================================
--- trunk/src/gui/gui_environment.cc	(revision 238)
+++ trunk/src/gui/gui_environment.cc	(revision 239)
@@ -22,5 +22,4 @@
 	*/
 
-#include "nv/interface/mesh.hh"
 #include "nv/gfx/sliced_buffer.hh"
 #include "nv/gfx/texture_atlas.hh"
