Index: /trunk/nv/formats/md2_loader.hh
===================================================================
--- /trunk/nv/formats/md2_loader.hh	(revision 238)
+++ /trunk/nv/formats/md2_loader.hh	(revision 239)
@@ -28,25 +28,11 @@
 		virtual ~md2_loader();
 		virtual bool load( stream& source );
-		virtual size_t get_size() { return m_size; }
-		virtual mesh_data_old* release_mesh_data();
-		virtual mesh_data_old* get_frame( sint32 frame );
-
-//		virtual mesh* release_mesh();
-//		virtual mesh* get_frame( sint32 frame );
-//		virtual const md3_tag* get_tag( const std::string& name ) const;
-//		virtual mat4 get_tag( sint32 frame, const std::string& name ) const;
+		virtual mesh_data* release_mesh_data();
+		virtual mesh_data* release_mesh_data( sint32 frame );
 		size_t get_max_frames() const;
-//		void load_tag_names( std::vector< std::string >& tags );
-//		void load_tags( std::vector<mat4>& t, const std::string& tag );
-		void load_positions( std::vector<vec3>& p, sint32 frame =-1 );
-		void load_normals( std::vector<vec3>& n, sint32 frame =-1 );
-		void load_texcoords( std::vector<vec2>& t );
-		void load_indicies( std::vector<uint32>& idx );
 	private:
 		void reindex();
 	private:
 		void* m_md2;
-//		std::unordered_map< std::string, md3_tag > m_tags;
-		std::size_t m_size;
 		std::vector< uint16 > m_new_indexes;
 		std::vector< uint16 > m_new_vindexes;
Index: /trunk/nv/formats/md3_loader.hh
===================================================================
--- /trunk/nv/formats/md3_loader.hh	(revision 238)
+++ /trunk/nv/formats/md3_loader.hh	(revision 239)
@@ -18,15 +18,9 @@
 #include <vector>
 #include <nv/transform.hh>
-#include <nv/gfx/mesh_data.hh>
+#include <nv/interface/mesh_data.hh>
 #include <nv/interface/mesh_loader.hh>
 
 namespace nv 
 {
-
-	struct md3_tag
-	{
-		std::string name;
-		transform   trans;
-	};
 
 	class md3_loader : public mesh_loader
@@ -36,21 +30,19 @@
 		virtual ~md3_loader();
 		virtual bool load( stream& source );
-		virtual size_t get_size() { return m_size; }
-		virtual mesh_data_old* release_mesh_data();
-		virtual mesh_data_old* get_frame( sint32 frame );
+		virtual mesh_data* release_mesh_data();
+		virtual mesh_data* release_mesh_data( sint32 frame );
+		size_t get_max_frames() const;
+		virtual tag_map* create_tag_map();
+	private:
+		void load_tags( std::vector<transform>& t, const std::string& tag );
+		void* m_md3;
 
-		virtual const md3_tag* get_tag( const std::string& name ) const;
-		virtual transform get_tag( sint32 frame, const std::string& name ) const;
-		size_t get_max_frames() const;
-		void load_tag_names( std::vector< std::string >& tags );
-		void load_tags( std::vector<transform>& t, const std::string& tag );
-		void load_positions( std::vector<vec3>& p, sint32 frame =-1 );
-		void load_normals( std::vector<vec3>& n, sint32 frame =-1 );
-		void load_texcoords( std::vector<vec2>& t );
-		void load_indicies( std::vector<uint32>& idx );
-	private:
-		void* m_md3;
+		struct md3_tag
+		{
+			std::string name;
+			transform   trans;
+		};
+
 		std::unordered_map< std::string, md3_tag > m_tags;
-		std::size_t m_size;
 	};
 
Index: /trunk/nv/formats/md5_loader.hh
===================================================================
--- /trunk/nv/formats/md5_loader.hh	(revision 238)
+++ /trunk/nv/formats/md5_loader.hh	(revision 239)
@@ -22,8 +22,36 @@
 {
 
+	struct md5_vtx_pnt
+	{
+		vec3 position;
+		vec3 normal;
+		vec3 tangent;
+	};
+
+	struct md5_vtx_t
+	{
+		vec2 texcoord;
+	};
+
+	struct md5_vtx_data
+	{
+		glm::vec3 normal;
+		glm::vec3 tangent;
+		size_t    start_weight;
+		size_t    weight_count;
+	};
+
+	struct md5_weight
+	{
+		size_t    joint_id;
+		float     bias;
+		glm::vec3 pos;
+	};
+
 	class md5_animation
 	{
 	protected:
 		friend class md5_loader;
+		friend class md5_mesh_data;
 		struct md5_joint_info
 		{
@@ -137,4 +165,19 @@
 	};
 
+	class md5_mesh_data : public mesh_data
+	{
+	public:
+		friend class md5_loader;
+
+		void apply( const md5_animation& animation );
+	private:
+		uint32*                     m_idata;
+		md5_vtx_t*                  m_tdata;
+		md5_vtx_pnt*                m_pntdata;
+		std::string                 m_shader;
+		std::vector< md5_vtx_data > m_vtx_data;
+		std::vector< md5_weight   > m_weights;
+	};
+
 
 	class md5_loader : public mesh_loader
@@ -142,51 +185,10 @@
 	public:
 		md5_loader() {}
-		virtual ~md5_loader() {}
+		virtual ~md5_loader();
 		virtual bool load( stream& source );
-		virtual size_t get_size();
-		virtual mesh_data_old* release_mesh_data() { return release_submesh_data(0); }
-		virtual mesh_data_old* release_submesh_data( uint32 mesh_id );
-//		virtual mesh* get_frame( sint32 /*frame*/ ) { return nullptr; }
+		virtual mesh_data* release_mesh_data() { return release_mesh_data( 0 ); }
+		virtual mesh_data* release_mesh_data( uint32 mesh );
 		bool check_animation( const md5_animation& animation ) const;
-		void apply( const md5_animation& animation );
-//		virtual const md3_tag* get_tag( const std::string& name ) const;
-//		virtual mat4 get_tag( sint32 frame, const std::string& name ) const;
-//		size_t get_max_frames() const;
-//		void load_tag_names( std::vector< std::string >& tags );
-//		void load_tags( std::vector<mat4>& t, const std::string& tag );
-//		void load_positions( std::vector<vec3>& p, sint32 frame =-1 );
-//		void load_normals( std::vector<vec3>& n, sint32 frame =-1 );
-//		void load_texcoords( std::vector<vec2>& t );
-//		void load_indicies( std::vector<uint16>& idx );
-	protected:
-		typedef std::vector<glm::vec3> md5_vec_buffer;
-		typedef std::vector<glm::vec2> md5_tc_buffer;
-		typedef std::vector<uint32> md5_index_buffer;
-
-		struct md5_vertex
-		{
-			glm::vec3 position;
-			glm::vec3 normal;
-			glm::vec3 tangent;
-			glm::vec2 texcoord;
-			size_t    start_weight;
-			size_t    weight_count;
-		};
-
-		typedef std::vector<md5_vertex> md5_vertex_list;
-
-		struct md5_triangle
-		{
-			size_t indices[3];
-		};
-		typedef std::vector<md5_triangle> md5_triangle_list;
-
-		struct md5_weight
-		{
-			size_t    joint_id;
-			float     bias;
-			glm::vec3 pos;
-		};
-		typedef std::vector<md5_weight> md5_weight_list;
+	protected:
 
 		struct md5_joint
@@ -197,32 +199,6 @@
 			quat  orient;
 		};
-		typedef std::vector<md5_joint> md5_joint_list;
-
-		struct md5_mesh
-		{
-			std::string       shader;
-			md5_vertex_list   verts;
-			md5_triangle_list tris;
-			md5_weight_list   weights;
-
-			md5_vec_buffer    position_buffer; 
-			md5_vec_buffer    normal_buffer;
-			md5_vec_buffer    tangent_buffer;
-			md5_tc_buffer     texcoord_buffer;
-			md5_index_buffer  index_buffer;
-		};
-		typedef std::vector<md5_mesh*> md5_mesh_list;
-	public:
-		const md5_vec_buffer&   get_positions( uint32 mesh_id ) const { return m_meshes[mesh_id]->position_buffer; }
-		const md5_vec_buffer&   get_normals  ( uint32 mesh_id ) const { return m_meshes[mesh_id]->normal_buffer; }
-		const md5_vec_buffer&   get_tangents ( uint32 mesh_id ) const { return m_meshes[mesh_id]->tangent_buffer; }
-		const md5_tc_buffer&    get_texcoords( uint32 mesh_id ) const { return m_meshes[mesh_id]->texcoord_buffer; }
-		const md5_index_buffer& get_indices  ( uint32 mesh_id ) const { return m_meshes[mesh_id]->index_buffer; }
-		size_t get_vertex_count( uint32 mesh_id ) const { return m_meshes[mesh_id]->position_buffer.size(); }
-		size_t get_index_count( uint32 mesh_id )  const { return m_meshes[mesh_id]->index_buffer.size(); }
-	protected:
-		bool prepare_mesh( md5_mesh* mesh );
-		bool prepare_normals( md5_mesh* mesh );
-		bool prepare_animated_mesh( md5_mesh* mesh, const md5_animation::md5_frame_skeleton& skel );
+	protected:
+		bool prepare_mesh( md5_mesh_data* mdata );
 	protected:
 		uint32 m_md5_version;
@@ -230,12 +206,6 @@
 		uint32 m_num_meshes;
 
-		md5_joint_list m_joints;
-		md5_mesh_list  m_meshes;
-
-		//bool           m_animation_present;
-		//md5_animation m_animation;
-
-		size_t m_size;
-		glm::mat4x4     m_model_matrix;
+		std::vector<md5_joint>      m_joints;
+		std::vector<md5_mesh_data*> m_meshes;
 	};
 
Index: /trunk/nv/formats/obj_loader.hh
===================================================================
--- /trunk/nv/formats/obj_loader.hh	(revision 238)
+++ /trunk/nv/formats/obj_loader.hh	(revision 239)
@@ -24,22 +24,8 @@
 	{
 	public:
-		obj_loader( bool tangents = false );
-		virtual ~obj_loader();
-		virtual bool load( stream& source );
-		virtual size_t get_size() { return m_size; }
-		virtual mesh_data_old* release_mesh_data() { mesh_data_old* m = m_mesh; m_mesh = nullptr; return m; }
-	private:
-		mesh_data_old*  m_mesh;
-		bool            m_tangents;
-		std::size_t     m_size;
-	};
-
-	class wavefront_loader 
-	{
-	public:
-		wavefront_loader( bool normals = true, bool tangents = false );
+		obj_loader( bool normals = true, bool tangents = false );
 		virtual bool load( stream& source );
 		mesh_data* release_mesh_data();
-		~wavefront_loader();
+		~obj_loader();
 	private:
 		vertex_descriptor m_descriptor;
@@ -49,5 +35,4 @@
 	};
 
-
 }
 
Index: /trunk/nv/gfx/keyframed_mesh.hh
===================================================================
--- /trunk/nv/gfx/keyframed_mesh.hh	(revision 238)
+++ /trunk/nv/gfx/keyframed_mesh.hh	(revision 239)
@@ -37,6 +37,6 @@
 	{
 	public:
-		keyframed_mesh( context* a_context, mesh_data_old* a_data );
-		virtual size_t get_index_count() const { return m_data->get_index_count(); }
+		keyframed_mesh( context* a_context, mesh_data* a_data, tag_map* a_tag_map );
+		virtual size_t get_index_count() const { return m_index_count; }
 		virtual void run_animation( animation_entry* a_anim );
 		size_t get_max_frames() const;
@@ -48,5 +48,12 @@
 		virtual ~keyframed_mesh();
 	protected:
-		mesh_data_old* m_data;
+		struct vertex_pn
+		{
+			vec3 position;
+			vec3 normal;
+		};
+
+		mesh_data* m_mesh_data;
+		tag_map*   m_tag_map;
 
 		uint32 m_start_frame;
@@ -59,4 +66,8 @@
 		bool   m_looping;
 		bool   m_active;
+
+		uint32 m_index_count;
+		uint32 m_frame_count;
+		uint32 m_vertex_count;
 	};
 
@@ -65,5 +76,5 @@
 	{
 	public:
-		keyframed_mesh_gpu( context* a_context, mesh_data_old* a_data, program* a_program );
+		keyframed_mesh_gpu( context* a_context, mesh_data* a_data, tag_map* a_tag_map, program* a_program );
 		void update( uint32 ms );
 	private:
@@ -78,11 +89,9 @@
 	{
 	public:
-		keyframed_mesh_cpu( context* a_context, mesh_data_old* a_data );
+		keyframed_mesh_cpu( context* a_context, mesh_data* a_data, tag_map* a_tag_map );
 		void update( uint32 ms );
 	private:
-		std::vector<vec3> m_position;
-		std::vector<vec3> m_normal;
-		vertex_buffer* m_vb_position;
-		vertex_buffer* m_vb_normal;
+		std::vector<vertex_pn> m_vertex;
+		vertex_buffer*         m_vb;
 	};
 
Index: unk/nv/gfx/mesh_data.hh
===================================================================
--- /trunk/nv/gfx/mesh_data.hh	(revision 238)
+++ 	(revision )
@@ -1,97 +1,0 @@
-// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
-// http://chaosforge.org/
-//
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-
-#ifndef NV_MESH_DATA_OLD_HH
-#define NV_MESH_DATA_OLD_HH
-
-#include <nv/common.hh>
-#include <unordered_map>
-#include <vector>
-#include <nv/math.hh>
-#include <nv/transform.hh>
-#include <nv/interface/device.hh>
-
-namespace nv
-{
-	class mesh_data_old
-	{
-	public:
-		friend class mesh_data_creator;
-		typedef std::vector< transform > transforms;
-		typedef std::unordered_map< std::string, transforms > tag_map;
-
-		mesh_data_old() {}
-
-		const std::vector< vec3 >&   get_positions() const { return m_positions; }
-		const std::vector< vec3 >&   get_normals()   const { return m_normals; }
-		const std::vector< vec3 >&   get_tangents()  const { return m_tangents; }
-		const std::vector< vec2 >&   get_texcoords() const { return m_texcoords; }
-		const std::vector< uint32 >& get_indices()   const { return m_indices; }
-
-		const mesh_data_old::tag_map&    get_tag_map()   const { return m_tags; }
-
-		size_t get_frame_count() const  { return m_texcoords.size() == 0 ? 0 : m_positions.size() / m_texcoords.size(); }
-		size_t get_index_count() const  { return m_indices.size(); }
-		size_t get_vertex_count() const { return m_texcoords.size(); }
-
-		const vec3* get_position_frame( uint32 frame = 0 ) { return m_positions.data() + m_texcoords.size() * frame; }
-		const vec3* get_normal_frame  ( uint32 frame = 0 ) { return m_normals.data() + m_texcoords.size() * frame; }
-		const vec3* get_tangent_frame ( uint32 frame = 0 ) { return m_tangents.data() + m_texcoords.size() * frame; }
-
-		bool has_tags()     const { return m_tags.size() > 0;  }
-		bool has_frames()   const { return get_frame_count() > 1;  }
-		bool has_normals()  const { return m_normals.size() > 0;  }
-		bool has_tangents() const { return m_tangents.size() > 0; }
-
-	protected:
-		tag_map               m_tags;
-		std::vector< vec3 >   m_normals;
-		std::vector< vec3 >   m_positions;
-		std::vector< vec3 >   m_tangents;
-		std::vector< vec2 >   m_texcoords;
-		std::vector< uint32 > m_indices;
-	};
-
-	class mesh_data_creator
-	{
-	public:
-		mesh_data_creator() 
-		{
-			m_data = new mesh_data_old;
-		}
-
-		const std::vector< vec3 >&   get_positions() const { return m_data->m_positions; }
-		const std::vector< vec3 >&   get_normals()   const { return m_data->m_normals; }
-		const std::vector< vec3 >&   get_tangents()  const { return m_data->m_tangents; }
-		const std::vector< vec2 >&   get_texcoords() const { return m_data->m_texcoords; }
-		const std::vector< uint32 >& get_indices()   const { return m_data->m_indices; }
-		const mesh_data_old::tag_map&    get_tag_map()   const { return m_data->m_tags; }
-
-		std::vector< vec3 >&   get_positions() { return m_data->m_positions; }
-		std::vector< vec3 >&   get_normals()   { return m_data->m_normals; }
-		std::vector< vec3 >&   get_tangents()  { return m_data->m_tangents; }
-		std::vector< vec2 >&   get_texcoords() { return m_data->m_texcoords; }
-		std::vector< uint32 >& get_indices()   { return m_data->m_indices; }
-		mesh_data_old::tag_map&    get_tag_map()   { return m_data->m_tags; }
-
-		mesh_data_old* release()
-		{
-			mesh_data_old* result = m_data;
-			m_data = nullptr;
-			return result;
-		}
-
-		~mesh_data_creator()
-		{
-			if ( m_data ) delete m_data;
-		}
-	private:
-		mesh_data_old* m_data;
-	};
-
-}
-
-#endif // NV_MESH_DATA_OLD_HH
Index: /trunk/nv/gfx/skeletal_mesh.hh
===================================================================
--- /trunk/nv/gfx/skeletal_mesh.hh	(revision 238)
+++ /trunk/nv/gfx/skeletal_mesh.hh	(revision 239)
@@ -31,9 +31,10 @@
 	};
 
+	// TODO: INSTANCING! currently md5_mesh data is deleted!
 	class skeletal_mesh : public animated_mesh
 	{
 	public:
-		skeletal_mesh( context* a_context, md5_loader* a_loader );
-		virtual size_t get_index_count() const { return m_data->get_index_count(0); }
+		skeletal_mesh( context* a_context, md5_mesh_data* a_mesh_data );
+		virtual size_t get_index_count() const { return m_mesh_data->get_count(); }
 		virtual void run_animation( animation_entry* a_anim );
 		virtual void setup_animation( md5_animation* a_anim );
@@ -41,9 +42,5 @@
 		virtual ~skeletal_mesh();
 	protected:
-		vertex_buffer* m_vb_position;
-		vertex_buffer* m_vb_normal;
-		vertex_buffer* m_vb_tangent;
-
-		md5_loader*    m_data;
+		md5_mesh_data* m_mesh_data;
 		md5_animation* m_animation;
 	};
Index: /trunk/nv/interface/device.hh
===================================================================
--- /trunk/nv/interface/device.hh	(revision 238)
+++ /trunk/nv/interface/device.hh	(revision 239)
@@ -15,5 +15,4 @@
 #include <nv/common.hh>
 #include <nv/string.hh>
-#include <nv/interface/mesh.hh>
 #include <nv/interface/mesh_data.hh>
 #include <nv/interface/vertex_buffer.hh>
@@ -38,22 +37,4 @@
 		virtual uint32 get_ticks() = 0;
 		virtual void delay( uint32 ms ) = 0;
-
-		virtual vertex_array* create_vertex_array( const mesh_pack* m, const attribute_map* am, buffer_hint hint )
-		{
-			vertex_array* result = create_vertex_array();
-			for ( auto& attr : m->get_attributes() )
-			{
-				// TODO : error checking
-				vertex_buffer* vb = create_vertex_buffer( hint, attr.second->get_size(), attr.second->get_data() );
-				result->add_vertex_buffer( am->at( attr.first )->get_location(), vb, attr.second->get_base_type(), attr.second->get_components() );
-			}
-			if ( m->has_indices() )
-			{
-				const vertex_attribute_base* i = m->get_indices();
-				index_buffer* vb = create_index_buffer( hint, i->get_size(), i->get_data() );
-				result->set_index_buffer( vb, i->get_base_type(), true );
-			}
-			return result;
-		}
 
 		template < typename VTX, slot SLOT >
@@ -121,10 +102,5 @@
 				const mesh_raw_channel* channel = data->get_channel_data()[ch];
 				vertex_buffer* vb = create_vertex_buffer( hint, channel->size, channel->data );
-				for ( uint32 s = 0; s < channel->desc.count; ++s )
-				{
-					const vertex_descriptor_slot& slot = channel->desc.slots[s];
-					const datatype_info&          info = get_datatype_info(slot.etype);
-					va->add_vertex_buffer( slot.vslot, vb, info.base , info.elements, slot.offset, channel->desc.size, false );
-				}
+				va->add_vertex_buffers( vb, channel );
 			}
 			if ( data->get_index_channel() != nullptr )
Index: unk/nv/interface/mesh.hh
===================================================================
--- /trunk/nv/interface/mesh.hh	(revision 238)
+++ 	(revision )
@@ -1,137 +1,0 @@
-// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
-// http://chaosforge.org/
-//
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-
-/**
- * @file mesh.hh
- * @author Kornel Kisielewicz
- * @brief mesh
- */
-
-#ifndef NV_MESH_HH
-#define NV_MESH_HH
-
-#include <nv/common.hh>
-#include <nv/string.hh>
-#include <nv/math.hh>
-#include <nv/interface/context.hh>
-#include <unordered_map>
-#include <vector>
-
-namespace nv
-{
-	class vertex_attribute_base
-	{
-	public:
-		vertex_attribute_base( const string& name, datatype attrtype ) 
-			: m_name( name ), m_type( attrtype ) {}
-		const string& get_name() const { return m_name; }
-		datatype get_type() const { return m_type; }
-		virtual datatype get_base_type() const = 0;
-		virtual size_t get_components() const = 0;
-		virtual size_t get_count() const = 0;
-		virtual size_t get_size() const = 0;
-		virtual void* get_data() const = 0;
-		virtual ~vertex_attribute_base() {}
-	private:
-		string m_name;
-		datatype  m_type;
-	};
-
-	template< typename T >
-	class vertex_attribute : public vertex_attribute_base
-	{
-	public:
-		typedef T value_type;
-		typedef typename datatype_traits<T>::base_type base_type;
-		typedef std::vector<T> list;
-
-		vertex_attribute( const string& name ) : vertex_attribute_base( name, type_to_enum<T>::type ) {}
-		const list& get() const { return m_list; }
-		list& get() { return m_list; }
-		virtual datatype get_base_type() const { return type_to_enum<base_type>::type; }
-		virtual size_t get_components() const { return datatype_traits<T>::size; }
-		virtual size_t get_count() const { return m_list.size(); }
-		virtual size_t get_size() const { return m_list.size() * sizeof(T); }
-		virtual void* get_data() const { return (void*)m_list.data(); }
-	private:
-		list m_list;
-	};
-
-
-	class mesh_pack
-	{
-	public:
-		typedef std::unordered_map< std::string, vertex_attribute_base* > map;
-
-		mesh_pack( primitive p = TRIANGLES ) 
-			: m_map(), m_indices(), m_primitive( p ) {}
-		template <typename T>
-		vertex_attribute<T>* add_attribute( const string& attr ) 
-		{ 
-			vertex_attribute<T>* result = new vertex_attribute<T>( attr ); 
-			m_map[ attr ] = result;
-			return result;
-		}
-		template <typename T>
-		vertex_attribute<T>* add_indices() 
-		{ 
-			if ( m_indices ) delete m_indices; // error?
-			vertex_attribute<T>* result = new vertex_attribute<T>(""); 
-			m_indices = result; 
-			return result;
-		}
-
-		vertex_attribute_base* get_attribute( const string& attr )
-		{
-			map::iterator i = m_map.find( attr );
-			return i != m_map.end() ? i->second : nullptr;
-		}
-
-		template <typename T>
-		vertex_attribute<T>* get_attribute( const string& attr )
-		{
-			map::iterator i = m_map.find( attr );
-			if ( i != m_map.end() && i->second->get_type() == type_to_enum<T>::type ) 
-			{
-				return ((vertex_attribute<T>*)(i->second));
-			}
-			return nullptr;
-		}
-
-		const vertex_attribute_base* get_indices() const { return m_indices; }
-		vertex_attribute_base* get_indices() { return m_indices; }
-
-		template <typename T>
-		vertex_attribute<T>* get_indices() 
-		{
-			return m_indices->get_type() == type_to_enum<T>() ? ((vertex_attribute<T>*)(m_indices)) : nullptr; 
-		}
-
-		const map& get_attributes() const { return m_map; }
-		primitive get_primitive() const { return m_primitive; }
-		bool has_indices() const { return m_indices != nullptr; }
-
-		~mesh_pack() 
-		{
-			delete m_indices;
-			for ( auto& v : m_map )
-			{
-				delete v.second;
-			}
-		}
-	private:
-		map                    m_map;
-		vertex_attribute_base* m_indices;
-		primitive              m_primitive;
-	};
-
-
-
-}
-
-
-#endif // NV_MESH_HH
-
Index: /trunk/nv/interface/mesh_data.hh
===================================================================
--- /trunk/nv/interface/mesh_data.hh	(revision 238)
+++ /trunk/nv/interface/mesh_data.hh	(revision 239)
@@ -9,10 +9,14 @@
 
 #include <nv/common.hh>
+#include <vector>
 #include <nv/math.hh>
-#include <nv/interface/context.hh>
 #include <nv/interface/vertex.hh>
 
 namespace nv
 {
+
+	// TODO: friend mesh_data_creator class?
+	// TODO: private const etc
+
 
 	struct mesh_raw_channel
@@ -27,4 +31,15 @@
 		{
 			if ( data != nullptr ) delete[] data;
+		}
+
+		template < typename VTX >
+		static mesh_raw_channel* create( uint32 count = 0 )
+		{
+			mesh_raw_channel* result = new mesh_raw_channel();
+			result->desc.initialize<VTX>();
+			result->count = count;
+			result->size  = count * sizeof( VTX );
+			result->data  = (count > 0 ? ( new uint8[ result->size ] ) : nullptr );
+			return result;
 		}
 	};
@@ -42,8 +57,15 @@
 			if ( data != nullptr ) delete[] data;
 		}
-	};
 
-	struct mesh_raw_data
-	{
+		template < typename ITYPE >
+		static mesh_raw_index_channel* create( uint32 count = 0 )
+		{
+			mesh_raw_index_channel* result = new mesh_raw_index_channel();
+			result->etype = type_to_enum< ITYPE >::type;
+			result->count = count;
+			result->size  = count * sizeof( ITYPE );
+			result->data  = (count > 0 ? ( new uint8[ result->size ] ) : nullptr );
+			return result;
+		}
 	};
 
@@ -75,5 +97,5 @@
 		}
 
-		~mesh_data()
+		virtual ~mesh_data()
 		{
 			for ( auto channel : m_channels ) delete channel;
Index: /trunk/nv/interface/mesh_loader.hh
===================================================================
--- /trunk/nv/interface/mesh_loader.hh	(revision 238)
+++ /trunk/nv/interface/mesh_loader.hh	(revision 239)
@@ -15,10 +15,32 @@
 
 #include <nv/common.hh>
+#include <vector>
+#include <unordered_map>
+#include <nv/transform.hh>
 #include <nv/string.hh>
+#include <nv/interface/mesh_data.hh>
 #include <nv/interface/stream.hh>
-#include <nv/gfx/mesh_data.hh>
 
 namespace nv 
 {
+
+	class tag_map
+	{
+	public:
+		typedef std::vector< transform > transforms;
+		typedef std::unordered_map< std::string, transforms > map;
+
+		tag_map () {}
+		map& get_map()             { return m_map; }
+		const map& get_map() const { return m_map; }
+		const transforms* get_tag( const std::string& key ) const
+		{
+			auto it = m_map.find( key );
+			return ( it != m_map.end() ? &(it->second) : nullptr );
+		}
+	private:
+		map m_map;
+	};
+
 
 	class mesh_loader
@@ -27,7 +49,7 @@
 		mesh_loader() {}
 		virtual ~mesh_loader() {}
+		virtual tag_map* create_tag_map() { return nullptr; }
 		virtual bool load( stream& source ) = 0;
-		virtual size_t get_size() = 0;
-		virtual mesh_data_old* release_mesh_data() = 0;
+		virtual mesh_data* release_mesh_data() = 0;
 	};
 
Index: /trunk/nv/interface/vertex_buffer.hh
===================================================================
--- /trunk/nv/interface/vertex_buffer.hh	(revision 238)
+++ /trunk/nv/interface/vertex_buffer.hh	(revision 239)
@@ -15,4 +15,6 @@
 #include <nv/common.hh>
 #include <nv/math.hh>
+#include <nv/interface/vertex.hh>
+#include <nv/interface/mesh_data.hh>
 #include <unordered_map>
 #include <string>
@@ -99,4 +101,19 @@
 			m_map[ location ] = p;
 		}
+
+		void add_vertex_buffers( vertex_buffer* buffer, const mesh_raw_channel* channel )
+		{
+			for ( uint32 s = 0; s < channel->desc.count; ++s )
+			{
+				add_vertex_buffer( buffer, channel->desc.slots[s], channel->desc.size );
+			}
+		}
+
+		void add_vertex_buffer( vertex_buffer* buffer, const vertex_descriptor_slot& slot, size_t vtx_size )
+		{
+			const datatype_info& info = get_datatype_info(slot.etype);
+			add_vertex_buffer( slot.vslot, buffer, info.base , info.elements, slot.offset, vtx_size, false );
+		}
+
 		void update_vertex_buffer( int location, vertex_buffer* b, bool owner ) 
 		{
@@ -127,4 +144,13 @@
 			m_index       = buffer; 
 		}
+		vertex_buffer* find_buffer( int location )
+		{
+			auto i = m_map.find( location );
+			if ( i != m_map.end() )
+			{
+				return i->second->get_buffer();
+			}
+			return nullptr;
+		}
 		bool has_index_buffer() const { return m_index != nullptr; }
 		datatype get_index_buffer_type() const { return m_index_type; }
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"
Index: /trunk/tests/gui_test/nv_gui_test.cc
===================================================================
--- /trunk/tests/gui_test/nv_gui_test.cc	(revision 238)
+++ /trunk/tests/gui_test/nv_gui_test.cc	(revision 239)
@@ -1,4 +1,5 @@
 #include <nv/gl/gl_device.hh>
 #include <nv/gui/gui_environment.hh>
+#include <nv/interface/context.hh>
 #include <nv/logging.hh>
 #include <nv/logger.hh>
Index: /trunk/tests/md2_test/md2_test.cc
===================================================================
--- /trunk/tests/md2_test/md2_test.cc	(revision 238)
+++ /trunk/tests/md2_test/md2_test.cc	(revision 239)
@@ -1,4 +1,3 @@
 #include <nv/common.hh>
-#include <iomanip>
 #include <nv/gfx/keyframed_mesh.hh>
 #include <nv/interface/vertex_buffer.hh>
@@ -18,61 +17,5 @@
 #include <nv/time.hh>
 #include <nv/string.hh>
-#include <nv/interface/mesh.hh>
 #include <glm/gtx/rotate_vector.hpp>
-#include <glm/gtc/matrix_access.hpp>
-#include <glm/gtx/matrix_interpolation.hpp>
-
-class mesh_part
-{
-public:
-	mesh_part( const std::string& path, nv::program* program, nv::window* window )
-	{
-		NV_PROFILE("mesh_construct");
-		nv::md2_loader* loader;
-		{
-			NV_PROFILE("loader->load");
-			nv::c_file_system fs;
-			nv::stream* mesh_file = fs.open( path.c_str() );
-			loader = new nv::md2_loader();
-			loader->load( *mesh_file );
-			m_mesh_data = loader->release_mesh_data();
-			delete mesh_file;
-			delete loader;
-		}
-
-		{
-			NV_PROFILE("create_mesh");
-			m_mesh      = new nv::keyframed_mesh_gpu( window->get_context(), m_mesh_data, program );
-		}
-
-	}
-
-	void setup_animation( nv::uint32 start, nv::uint32 stop, nv::uint32 fps, bool loop )
-	{
-		m_mesh->setup_animation( start, stop, fps, loop );
-	}
-
-	void update( nv::uint32 ms )
-	{
-		m_mesh->update( ms );
-	}
-
-	nv::mesh_interface* get_mesh() { return m_mesh; }
-
-	size_t get_max_frames()
-	{
-		return m_mesh->get_max_frames();
-	}
-
-	~mesh_part()
-	{
-		delete m_mesh_data;
-		delete m_mesh;
-	}
-
-private:
-	nv::mesh_data*       m_mesh_data;
-	nv::keyframed_mesh*  m_mesh;
-};
 
 class application
@@ -87,9 +30,12 @@
 	nv::window*       m_window;
 	nv::texture2d*    m_diffuse;
+	nv::program*      m_program;
+
 	nv::clear_state   m_clear_state;
 	nv::render_state  m_render_state;
+	nv::scene_state   m_scene_state;
 
-	mesh_part*   m_mesh;
-	nv::program* m_program;
+	nv::mesh_data*      m_mesh_data;
+	nv::keyframed_mesh* m_mesh;
 };
 
@@ -119,5 +65,22 @@
 	NV_PROFILE( "app_initialize" );
 	m_program = m_device->create_program( nv::slurp( "obj.vert" ), nv::slurp( "obj.frag" ) );
-	m_mesh    = new mesh_part( "data/manc.md2", m_program, m_window );
+
+	nv::md2_loader* loader;
+	{
+		NV_PROFILE("loader->load");
+		nv::c_file_system fs;
+		nv::stream* mesh_file = fs.open( "data/manc.md2" );
+		loader = new nv::md2_loader();
+		loader->load( *mesh_file );
+		m_mesh_data = loader->release_mesh_data();
+		delete mesh_file;
+		delete loader;
+	}
+
+	{
+		NV_PROFILE("create_mesh");
+		m_mesh      = new nv::keyframed_mesh_gpu( m_window->get_context(), m_mesh_data, nullptr, m_program );
+	}
+
 	return true;
 }
@@ -128,6 +91,4 @@
 	NV_PROFILE( "app_run" );
 	int keypress = 0;
-
-	glm::vec3 move( 0, 25.f, 0 );
 
 	nv::uint32 ticks   = m_device->get_ticks();
@@ -142,68 +103,40 @@
 		ticks      = m_device->get_ticks();
 		nv::uint32 elapsed = ticks - last_ticks;
+		m_window->get_context()->clear( m_clear_state );
 		m_mesh->update( elapsed );
-		{
-			NV_PROFILE( "clear" );
-			m_window->get_context()->clear( m_clear_state );
-		}
+		glm::vec3 eye = glm::rotate( glm::vec3( 100.0f, 25.0f, 0.0f ), (ticks / 20.f), glm::vec3( 0.0,1.0,0.0 ) );
 
-		glm::mat4 view;
-		glm::mat4 projection;
-		{
-			NV_PROFILE( "update_sh" );
+		m_scene_state.set_model( nv::mat4(1.0f) );
+		m_scene_state.get_camera().set_lookat(eye, glm::vec3(0.0f, 25.0f, 0.0f), glm::vec3(0.0, 1.0, 0.0));
+		m_scene_state.get_camera().set_perspective(60.0f, 1.0f*800.0f/600.0f, 0.1f, 1000.0f);
 
-			glm::vec3 source( 100.0f, 0.0f, 0.0f );
-			glm::vec3 eye = glm::rotate( source, (ticks / 20.f), glm::vec3( 0.0,1.0,0.0 ) );
+		m_diffuse->bind( 0 );
+		m_program->set_opt_uniform( "light_position", glm::vec3(120.0, 120.0, 0) );
+		m_program->set_opt_uniform( "light_diffuse",  glm::vec4(1.0,1.0,1.0,1.0) );
+		m_program->set_opt_uniform( "light_specular", glm::vec4(1.0,1.0,1.0,1.0) );
+		m_mesh->update( m_program );
+		m_window->get_context()->draw( m_render_state, m_scene_state, m_program, m_mesh );
+		m_window->swap_buffers();
 
-			view       = glm::lookAt(eye + move, glm::vec3(0.0f, 0.0f, 0.0f) + move, glm::vec3(0.0, 1.0, 0.0));
-			projection = glm::perspective(60.0f, 1.0f*800.0f/600.0f, 0.1f, 1000.0f);
-
-			m_diffuse->bind( 0 );
-			m_program->set_opt_uniform( "nv_m_projection", projection );
-			m_program->set_uniform( "light_position", glm::vec3(120.0, 120.0, 0) );
-			m_program->set_uniform( "light_diffuse",  glm::vec4(1.0,1.0,1.0,1.0) );
-			m_program->set_uniform( "light_specular", glm::vec4(1.0,1.0,1.0,1.0) );
-			m_program->set_uniform( "diffuse", 0 );
-		}
-
-		{
-			NV_PROFILE( "draw" );
-			glm::mat4 model      = glm::mat4(1.0f);
-			glm::mat4 mv = view * model;
-			m_program->set_opt_uniform( "nv_m_modelview", mv );
-			m_program->set_opt_uniform( "nv_m_normal", glm::transpose(glm::inverse(glm::mat3(mv))) );
-			m_program->set_uniform( "matrix_mvp", projection * mv );
-			m_mesh->get_mesh()->update( m_program );
-			m_window->get_context()->draw( m_render_state, m_program, m_mesh->get_mesh() );
-		}
-
-		{
-			NV_PROFILE( "swap" );
-			m_window->swap_buffers();
-		}
-
-		{
-			NV_PROFILE( "pollevent" );
-			nv::io_event event;
-			while(m_window->poll_event(event)) 
-			{      
-				switch (event.type) 
+		nv::io_event event;
+		while(m_window->poll_event(event)) 
+		{      
+			switch (event.type) 
+			{
+			case nv::EV_QUIT:
+				keypress = 1;
+				break;
+			case nv::EV_KEY:
+				if (event.key.pressed)
 				{
-				case nv::EV_QUIT:
-					keypress = 1;
-					break;
-				case nv::EV_KEY:
-					if (event.key.pressed)
+					switch (event.key.code) 
 					{
-						switch (event.key.code) 
-						{
-						case nv::KEY_ESCAPE : keypress = 1; break;
-						case nv::KEY_F1 : nv::profiler::pointer()->log_report(); break;
-						default: break;
-						}
+					case nv::KEY_ESCAPE : keypress = 1; break;
+					case nv::KEY_F1 : nv::profiler::pointer()->log_report(); break;
+					default: break;
 					}
-					break;
-				default: break;
 				}
+				break;
+			default: break;
 			}
 		}
@@ -216,4 +149,5 @@
 {
 	delete m_program;
+	delete m_mesh_data;
 	delete m_mesh;
 	delete m_diffuse;
Index: /trunk/tests/md2_test/obj.frag
===================================================================
--- /trunk/tests/md2_test/obj.frag	(revision 238)
+++ /trunk/tests/md2_test/obj.frag	(revision 239)
@@ -1,5 +1,5 @@
 #version 120
 
-uniform sampler2D diffuse;
+uniform sampler2D nv_t_diffuse;
 uniform vec4 light_diffuse;
 uniform vec4 light_specular;
@@ -9,26 +9,29 @@
 varying vec3 v_light_vector;
 varying vec3 v_view_vector;
- 
+
 void main(void) {
+	vec3 diff_texel      = vec3( texture2D( nv_t_diffuse, v_texcoord ) );	
+
 	vec3 nnormal         = normalize( v_normal );
 	vec3 nlight_vector   = normalize( v_light_vector );
-	vec3 nview_vector    = normalize( v_view_vector );
 	vec3 nreflect_vector = reflect( -nlight_vector, nnormal );
 
-	float specular_value = clamp( dot( nreflect_vector, nview_vector ), 0.0, 1.0 );
-	specular_value       = pow( specular_value, 6.0 );
-	float diffuse_value  = max( dot( nlight_vector, nnormal ), 0.0 );
+	float specular_amount = 0.2;
+	float diffuse_amount  = 1.0 - specular_amount;
 
-	vec3 diff_texel      = vec3( texture2D( diffuse, v_texcoord ) );	
-	
-	float final_specular = specular_value * 0.2;
-	float final_diffuse  = diffuse_value * 0.5;
-	float final_ambient  = 0.3;
+	float dot_prod_specular = dot( nreflect_vector, normalize( v_view_vector ) );
+	float dot_prod_diffuse  = dot( nlight_vector, nnormal );
 
-	vec3 ambient_color   = final_ambient * diff_texel;
-	vec3 diffuse_color   = light_diffuse.xyz * final_diffuse * diff_texel;
+	float diffuse_factor  = max( dot_prod_diffuse, 0.0 );
+	float specular_factor = pow( max( dot_prod_specular, 0.0 ), 16.0 ); // 100.0
+
+	float final_diffuse  = diffuse_amount * diffuse_factor * 0.5;
+	float final_specular = specular_amount * specular_factor;
+
+	vec3 diffuse_color   = light_diffuse.xyz  * final_diffuse * diff_texel;
 	vec3 specular_color  = light_specular.xyz * final_specular;
+	vec3 self_ilum_color = vec3 (0.0, 0.0, 0.0);
+	vec3 ambient_color   = vec3 (0.0, 0.0, 0.0);
 
-	gl_FragColor = vec4( ambient_color + diffuse_color + specular_color, 1.0 );
-//	gl_FragColor = vec4( diff_texel, 1.0 );
+	gl_FragColor = vec4( max( self_ilum_color, diffuse_color + specular_color + ambient_color ), 1.0 );
 }
Index: /trunk/tests/md2_test/obj.vert
===================================================================
--- /trunk/tests/md2_test/obj.vert	(revision 238)
+++ /trunk/tests/md2_test/obj.vert	(revision 239)
@@ -12,19 +12,22 @@
 varying vec2 v_texcoord;
 
-uniform mat4 matrix_mvp;
-uniform mat4 nv_m_modelview;
-uniform mat4 nv_m_projection;
-uniform mat3 nv_m_normal;
+uniform mat4 nv_m_mvp;
+uniform mat4 nv_m_model;
+uniform mat4 nv_m_model_inv;
+uniform vec3 nv_v_camera_position;
+uniform vec3 light_position;
 uniform float nv_interpolate;
-uniform vec3 light_position;
 
-void main(void) {
-	vec4 vertex     = vec4( mix( nv_position, nv_next_position, nv_interpolate ), 1.0 );
-	vec3 eye_pos    = vec3( nv_m_modelview * vertex );
-	v_normal        = normalize( nv_m_normal * mix( nv_normal, nv_next_normal, nv_interpolate ) );
-	v_light_vector  = vec3( normalize( light_position - eye_pos ) );
-	v_view_vector   = vec3( normalize( -eye_pos ) );
+void main(void)
+{
+	vec4 position   = vec4( mix( nv_position, nv_next_position, nv_interpolate ), 1.0 );
+	v_normal        = normalize( mix( nv_normal, nv_next_normal, nv_interpolate ) );
+	v_texcoord      = nv_texcoord;
+	gl_Position     = nv_m_mvp * position;
 
-	v_texcoord      = nv_texcoord;
-	gl_Position     = matrix_mvp * vertex;
+	vec3 camera_loc = vec3(nv_m_model_inv * vec4 (nv_v_camera_position, 1.0) );
+	vec3 light_loc  = vec3(nv_m_model_inv * vec4 (light_position, 1.0) );
+
+	v_view_vector  = normalize( nv_position - camera_loc  );
+	v_light_vector = normalize( nv_position - light_loc );
 }
Index: /trunk/tests/md3_test/md3_test.cc
===================================================================
--- /trunk/tests/md3_test/md3_test.cc	(revision 238)
+++ /trunk/tests/md3_test/md3_test.cc	(revision 239)
@@ -18,5 +18,4 @@
 #include <nv/time.hh>
 #include <nv/string.hh>
-#include <nv/interface/mesh.hh>
 #include <glm/gtx/rotate_vector.hpp>
 #include <glm/gtc/matrix_access.hpp>
@@ -43,5 +42,6 @@
 		{
 			NV_PROFILE("create_mesh_data");
-			m_data      = loader->release_mesh_data();
+			m_mesh_data = loader->release_mesh_data();
+			m_tag_map   = loader->create_tag_map();
 		}
 		delete loader;
@@ -50,7 +50,7 @@
 			NV_PROFILE("create_mesh");
 			if ( GPU_ANIMATION )
-				m_mesh      = new nv::keyframed_mesh_gpu( window->get_context(), m_data, program );
+				m_mesh      = new nv::keyframed_mesh_gpu( window->get_context(), m_mesh_data, m_tag_map, program );
 			else
-				m_mesh      = new nv::keyframed_mesh_cpu( window->get_context(), m_data );
+				m_mesh      = new nv::keyframed_mesh_cpu( window->get_context(), m_mesh_data, m_tag_map );
 		}
 
@@ -67,7 +67,8 @@
 	}
 
-	void update( nv::uint32 ms )
+	void update( nv::uint32 ms, nv::program* program )
 	{
 		m_mesh->update( ms );
+		m_mesh->update( program );
 	}
 
@@ -79,24 +80,15 @@
 	}
 
-	void draw( nv::context* c, nv::program* program, nv::render_state& rstate, const glm::mat4& m, const glm::mat4& v, const glm::mat4& p )
-	{
-		NV_PROFILE( "mesh-draw" );
-		glm::mat4 mv = v * m;
-		program->set_opt_uniform( "nv_m_modelview", mv );
-		program->set_opt_uniform( "nv_m_normal", glm::transpose(glm::inverse(glm::mat3(mv))) );
-		program->set_uniform( "matrix_mvp", p * mv );
-		
-		c->draw( rstate, program, m_mesh );
-	}
-
 	~mesh_part()
 	{
-		delete m_data;
+		delete m_tag_map;
+		delete m_mesh_data;
 		delete m_mesh;
 	}
 
 private:
-	nv::mesh_data*           m_data;
-	nv::keyframed_mesh*      m_mesh;
+	nv::tag_map*        m_tag_map;
+	nv::mesh_data*      m_mesh_data;
+	nv::keyframed_mesh* m_mesh;
 };
 
@@ -113,6 +105,8 @@
 	nv::texture2d*    m_diffuse;
 	nv::texture2d*    m_diffuse_weapon;
+
 	nv::clear_state   m_clear_state;
 	nv::render_state  m_render_state;
+	nv::scene_state   m_scene_state;
 
 	mesh_part* m_torso;
@@ -120,5 +114,5 @@
 	mesh_part* m_head;
 	mesh_part* m_weapon;
-	nv::program*      m_program;
+	nv::program* m_program;
 };
 
@@ -182,6 +176,6 @@
 		ticks      = m_device->get_ticks();
 		nv::uint32 elapsed = ticks - last_ticks;
-		m_torso->update( elapsed );
-		m_legs->update( elapsed );
+		m_torso->update( elapsed, m_program );
+		m_legs->update( elapsed, m_program );
 		{
 			NV_PROFILE( "clear" );
@@ -197,13 +191,11 @@
 			glm::vec3 eye = glm::rotate( source, (ticks / 20.f), glm::vec3( 0.0,1.0,0.0 ) );
 
-			view       = glm::lookAt(eye + move, glm::vec3(0.0f, 0.0f, 0.0f) + move, glm::vec3(0.0, 1.0, 0.0));
-			projection = glm::perspective(60.0f, 1.0f*800.0f/600.0f, 0.1f, 1000.0f);
+			m_scene_state.get_camera().set_lookat(eye + move, glm::vec3(0.0f, 0.0f, 0.0f) + move, glm::vec3(0.0, 1.0, 0.0));
+			m_scene_state.get_camera().set_perspective(60.0f, 1.0f*800.0f/600.0f, 0.1f, 1000.0f);
 
 			m_diffuse->bind( 0 );
-			m_program->set_opt_uniform( "nv_m_projection", projection );
 			m_program->set_uniform( "light_position", glm::vec3(120.0, 120.0, 0) );
 			m_program->set_uniform( "light_diffuse",  glm::vec4(1.0,1.0,1.0,1.0) );
 			m_program->set_uniform( "light_specular", glm::vec4(1.0,1.0,1.0,1.0) );
-			m_program->set_uniform( "diffuse", 0 );
 		}
 
@@ -211,16 +203,21 @@
 			NV_PROFILE( "draw" );
 			glm::mat4 model      = glm::mat4(1.0f);
-			m_legs->draw( m_window->get_context(), m_program, m_render_state, model, view, projection );
+
+			m_scene_state.set_model( model );
+			m_window->get_context()->draw( m_render_state, m_scene_state, m_program, m_legs->get_mesh() );
 
 			//model = m_legs->get_transform( "tag_torso", last_legs_frame, legs_frame, legs_interpolate );
 			model = m_legs->get_transform( "tag_torso" );
-			m_torso->draw( m_window->get_context(), m_program, m_render_state, model, view, projection );
+			m_scene_state.set_model( model );
+			m_window->get_context()->draw( m_render_state, m_scene_state, m_program, m_torso->get_mesh() );
 
 			glm::mat4 head = model * m_torso->get_transform( "tag_head" ); //, last_torso_frame, torso_frame, torso_interpolate );
-			m_head->draw( m_window->get_context(), m_program, m_render_state, head, view, projection );
+			m_scene_state.set_model( head );
+			m_window->get_context()->draw( m_render_state, m_scene_state, m_program, m_head->get_mesh() );
 
 			glm::mat4 weapon = model * m_torso->get_transform( "tag_weapon" ); //, last_torso_frame, torso_frame, torso_interpolate );
+			m_scene_state.set_model( weapon );
 			m_diffuse_weapon->bind( 0 );
-			m_weapon->draw( m_window->get_context(), m_program, m_render_state, weapon, view, projection );
+			m_window->get_context()->draw( m_render_state, m_scene_state, m_program, m_weapon->get_mesh() );
 
 		}
Index: /trunk/tests/md5_test/md5_test.cc
===================================================================
--- /trunk/tests/md5_test/md5_test.cc	(revision 238)
+++ /trunk/tests/md5_test/md5_test.cc	(revision 239)
@@ -18,84 +18,8 @@
 #include <nv/time.hh>
 #include <nv/string.hh>
-#include <nv/interface/mesh.hh>
 #include <nv/gfx/skeletal_mesh.hh>
 #include <glm/gtx/rotate_vector.hpp>
 #include <glm/gtc/matrix_access.hpp>
 #include <glm/gtx/matrix_interpolation.hpp>
-
-class mesh_part
-{
-public:
-	mesh_part( const std::string& path, nv::program* program, nv::window* window )
-		: m_mesh( nullptr ), m_program( program ), m_loader( nullptr ), m_animation( nullptr ), m_window( window )
-	{
-		
-		NV_PROFILE("mesh_construct");
-		{
-			NV_PROFILE("loader->load");
-			nv::c_file_system fs;
-			nv::stream* mesh_file = fs.open( path.c_str() );
-			m_loader = new nv::md5_loader();
-			m_loader->load( *mesh_file );
-			delete mesh_file;
-		}
-
-		{
-			NV_PROFILE("create_mesh");
-			m_mesh = new nv::skeletal_mesh( window->get_context(), m_loader );
-		}
-
-	}
-
-	void load_animation( const std::string& path )
-	{
-		delete m_animation;
-		m_animation = nullptr;
-		NV_PROFILE("load_animation");
-		nv::c_file_system fs;
-		nv::stream* anim_file = fs.open( path.c_str() );
-
-		if ( anim_file != nullptr )
-		{
-			m_animation = new nv::md5_animation();
-			if ( !m_animation->load_animation(*anim_file) )
-			{
-				delete m_animation;
-				m_animation = nullptr;
-			}
-			m_mesh->setup_animation( m_animation );
-			delete anim_file;
-		}
-	}
-
-	void update( nv::uint32 ms )
-	{
-		m_mesh->update( ms );
-	}
-
-	void draw( nv::context* context, nv::render_state& rstate, const glm::mat4& m, const glm::mat4& v, const glm::mat4& p )
-	{
- 		NV_PROFILE( "mesh-draw" );
- 		glm::mat4 mv = v * m;
-		m_program->set_opt_uniform( "nv_m_model", m );
- 		m_program->set_opt_uniform( "nv_m_modelview", mv );
-		m_program->set_opt_uniform( "nv_m_view_inv", glm::inverse( v ) );
- 		m_program->set_opt_uniform( "nv_m_normal", glm::transpose(glm::inverse(glm::mat3(mv))) );
-		m_program->set_uniform( "matrix_mvp", p * mv );
-		context->draw( rstate, m_program, m_mesh );
-	}
-
-	~mesh_part()
-	{
- 		delete m_mesh;
-	}
-
-private:
-	nv::skeletal_mesh* m_mesh;
-	nv::program*       m_program;
-	nv::md5_loader*    m_loader;
-	nv::md5_animation* m_animation;
-	nv::window*        m_window;
-};
 
 class application
@@ -107,4 +31,8 @@
 	~application();
 protected:
+	void load_animation( const std::string& path );
+protected:
+
+
 	nv::device*       m_device;
 	nv::window*       m_window;
@@ -114,7 +42,11 @@
 	nv::clear_state   m_clear_state;
 	nv::render_state  m_render_state;
-
-	mesh_part*   m_mesh;
-	nv::program* m_program;
+	nv::scene_state   m_scene_state;
+
+	nv::skeletal_mesh* m_mesh;
+	nv::program*       m_program;
+	nv::md5_mesh_data* m_mesh_data;
+	nv::md5_animation* m_animation;
+
 };
 
@@ -124,4 +56,5 @@
 	m_device = new nv::gl_device();
 	m_window = m_device->create_window( 800, 600, false );
+	m_animation = nullptr;
 
 	nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::REPEAT );
@@ -152,6 +85,23 @@
 	NV_PROFILE( "app_initialize" );
 	m_program = m_device->create_program( nv::slurp( "md5.vert" ), nv::slurp( "md5.frag" ) );
-	m_mesh    = new mesh_part( "data/qshambler.md5mesh", m_program, m_window );
-	m_mesh->load_animation( "data/idle02.md5anim" );
+
+	nv::md5_loader* loader = nullptr;
+	{
+		NV_PROFILE("loader->load");
+		nv::c_file_system fs;
+		nv::stream* mesh_file = fs.open( "data/qshambler.md5mesh" );
+		loader = new nv::md5_loader();
+		loader->load( *mesh_file );
+		delete mesh_file;
+	}
+
+	{
+		NV_PROFILE("create_mesh");
+		m_mesh_data = (nv::md5_mesh_data*)loader->release_mesh_data();
+		m_mesh = new nv::skeletal_mesh( m_window->get_context(), m_mesh_data );
+		delete loader;
+	}
+
+	load_animation( "data/idle02.md5anim" );
 	return true;
 }
@@ -182,6 +132,4 @@
 		}
 
-		glm::mat4 view;
-		glm::mat4 projection;
 		{
 			NV_PROFILE( "update_sh" );
@@ -190,28 +138,25 @@
 			glm::vec3 eye = glm::rotate( source, (ticks / 20.f), glm::vec3( 0.0,1.0,0.0 ) );
 
-			view       = glm::lookAt(eye + move, glm::vec3(0.0f, 0.0f, 0.0f) + move, glm::vec3(0.0, 1.0, 0.0));
-			projection = glm::perspective(60.0f, 1.0f*800.0f/600.0f, 0.1f, 1000.0f);
+			m_scene_state.get_camera().set_lookat(eye + move, glm::vec3(0.0f, 0.0f, 0.0f) + move, glm::vec3(0.0, 1.0, 0.0));
+			m_scene_state.get_camera().set_perspective(60.0f, 1.0f*800.0f/600.0f, 0.1f, 1000.0f);
 
 			m_diffuse ->bind( 0 );
 			m_specular->bind( 1 );
 			m_normal  ->bind( 2 );
-			m_program->set_opt_uniform( "nv_m_projection", projection );
-			m_program->set_uniform( "light_position", glm::vec3(180.0, 180.0, 0) );
-			m_program->set_uniform( "light_diffuse",  glm::vec4(0.7,0.7,0.7,1.0) );
-			m_program->set_uniform( "light_specular", glm::vec4(1.0,1.0,1.0,1.0) );
-			m_program->set_uniform( "diffuse", 0 );
-			m_program->set_uniform( "specular", 1 );
-			m_program->set_uniform( "normalmap", 2 );
+			m_program->set_opt_uniform( "light_position", glm::vec3(180.0, 180.0, 0) );
+			m_program->set_opt_uniform( "light_diffuse",  glm::vec4(0.7,0.7,0.7,1.0) );
+			m_program->set_opt_uniform( "light_specular", glm::vec4(1.0,1.0,1.0,1.0) );
 		}
 
 		{
 			NV_PROFILE( "draw" );
-			glm::mat4 model      = 
-				glm::mat4(1.f,0.f,0.f,0.f,
-				          0.f,0.f,1.f,0.f,
-						  0.f,1.f,0.f,0.f,
-						  0.f,0.f,0.f,1.f);
-
-			m_mesh->draw( m_window->get_context(), m_render_state, model, view, projection );
+			m_scene_state.set_model(nv::mat4(
+				1.f,0.f,0.f,0.f,
+				0.f,0.f,1.f,0.f,
+				0.f,1.f,0.f,0.f,
+				0.f,0.f,0.f,1.f
+			) );
+
+			m_window->get_context()->draw( m_render_state, m_scene_state, m_program, m_mesh );
 		}
 
@@ -251,4 +196,26 @@
 }
 
+void application::load_animation( const std::string& path )
+{
+	delete m_animation;
+	m_animation = nullptr;
+	NV_PROFILE("load_animation");
+	nv::c_file_system fs;
+	nv::stream* anim_file = fs.open( path.c_str() );
+
+	if ( anim_file != nullptr )
+	{
+		m_animation = new nv::md5_animation();
+		if ( !m_animation->load_animation(*anim_file) )
+		{
+			delete m_animation;
+			m_animation = nullptr;
+		}
+		m_mesh->setup_animation( m_animation );
+		delete anim_file;
+	}
+}
+
+
 application::~application()
 {
Index: /trunk/tests/objload_test/objload_test.cc
===================================================================
--- /trunk/tests/objload_test/objload_test.cc	(revision 238)
+++ /trunk/tests/objload_test/objload_test.cc	(revision 239)
@@ -13,5 +13,4 @@
 #include <nv/math.hh>
 #include <nv/string.hh>
-#include <nv/interface/mesh.hh>
 
 class application
@@ -71,5 +70,5 @@
 // 		delete loader;
 
-	nv::wavefront_loader* loader = new nv::wavefront_loader();
+	nv::obj_loader* loader = new nv::obj_loader();
 	loader->load( *mesh_file );
 	m_mesh = loader->release_mesh_data();
Index: /trunk/tests/render_test/rl.cc
===================================================================
--- /trunk/tests/render_test/rl.cc	(revision 238)
+++ /trunk/tests/render_test/rl.cc	(revision 239)
@@ -10,5 +10,4 @@
 #include <nv/math.hh>
 #include <nv/string.hh>
-#include <nv/interface/mesh.hh>
 
 const nv::uint16 size_x  = 16;
