Index: trunk/nv/interface/mesh.hh
===================================================================
--- trunk/nv/interface/mesh.hh	(revision 71)
+++ trunk/nv/interface/mesh.hh	(revision 71)
@@ -0,0 +1,134 @@
+// 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/types.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
+	{
+	public:
+		typedef std::unordered_map< std::string, vertex_attribute_base* > map;
+
+		mesh( primitive p = TRIANGLES, culling::order_type c = culling::CCW ) 
+			: m_map(), m_indices(), m_primitive( p ), m_order( c ) {}
+		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?
+			m_indices = new vertex_attribute<T>( attr ); 
+			return m_indices;
+		}
+
+		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>() ) 
+			{
+				return ((vertex_attribute<T>*)(i->second));
+			}
+			return nullptr;
+		}
+
+		vertex_attribute_base* get_indices() { return m_indices; }
+
+		template <typename T>
+		vertex_attribute<T>* get_indices( const string& attr )
+		{
+			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() 
+		{
+			delete m_indices;
+			for ( auto v : m_map )
+			{
+				delete v.second;
+			}
+		}
+	private:
+		map                    m_map;
+		vertex_attribute_base* m_indices;
+		primitive              m_primitive;
+		culling::order_type    m_order;
+
+	};
+
+}
+
+
+#endif // NV_MESH_HH
+
Index: trunk/tests/render_test/rl.cc
===================================================================
--- trunk/tests/render_test/rl.cc	(revision 70)
+++ trunk/tests/render_test/rl.cc	(revision 71)
@@ -15,6 +15,5 @@
 #include <nv/string.hh>
 #include <nv/types.hh>
-
-typedef glm::detail::tvec3<char> byte3;
+#include <nv/interface/mesh.hh>
 
 const nv::uint16 size_x  = 16;
@@ -62,7 +61,4 @@
 };
 
-struct world;
-struct being;
-
 class application
 {
@@ -70,5 +66,5 @@
 	application();
 	bool initialize();
-	bool init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, int count, void* vertex, void* material );
+	bool init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, nv::mesh* m );
 	bool run();
 	~application();
@@ -110,22 +106,24 @@
 {
 	{ // CHARACTER
-		byte3 vertex[6];
-		byte3 material[6];
+		nv::mesh cmesh;
+		nv::vertex_attribute<nv::i8vec3>::list& vtx = cmesh.add_attribute<nv::i8vec3>("coords")->get();
+		nv::vertex_attribute<nv::i8vec3>::list& mat = cmesh.add_attribute<nv::i8vec3>("material")->get();
 		int m = 16;	int x = 0; int y = 0; int h = 0;
-		vertex[0] = byte3( x,   h, y );   material[0] = byte3( m, 1, 0 );
-		vertex[1] = byte3( x,   h, y+1 ); material[1] = byte3( m, 1, 0 );
-		vertex[2] = byte3( x+1, h, y+1 ); material[2] = byte3( m, 1, 0 );
-		vertex[3] = byte3( x+1, h, y+1 ); material[3] = byte3( m, 1, 0 );
-		vertex[4] = byte3( x+1, h, y );   material[4] = byte3( m, 1, 0 );
-		vertex[5] = byte3( x,   h, y );   material[5] = byte3( m, 1, 0 );
-
-		if (!init_program( "char", m_char_program, m_char_va, 6, vertex, material ) ) return false;
+		vtx.emplace_back( x,   h, y );  
+		vtx.emplace_back( x,   h, y+1 );
+		vtx.emplace_back( x+1, h, y+1 );
+		vtx.emplace_back( x+1, h, y+1 );
+		vtx.emplace_back( x+1, h, y );  
+		vtx.emplace_back( x,   h, y );  
+		mat.insert( mat.end(), 6, nv::i8vec3( m, 1, 0 ) );
+
+		if (!init_program( "char", m_char_program, m_char_va, &cmesh ) ) return false;
 	}
 
 	{ // WORLD
-		byte3 vertex[size_x * size_y * 256];
-		byte3 material[size_x * size_y * 256];
-		m_count = 0;
-		int mcount = 0;
+		nv::mesh wmesh;
+		nv::vertex_attribute<nv::i8vec3>::list& vtx = wmesh.add_attribute<nv::i8vec3>("coords")->get();
+		nv::vertex_attribute<nv::i8vec3>::list& mat = wmesh.add_attribute<nv::i8vec3>("material")->get();
+
 		for (int i = 0; i < size_x * size_y; ++i )
 		{
@@ -133,11 +131,11 @@
 			int y = i / size_x;
 
-			vertex[m_count++] = byte3( x,   height[i], y   ); material[mcount++] = byte3( map[i], 2, 0 );
-			vertex[m_count++] = byte3( x,   height[i], y+1 ); material[mcount++] = byte3( map[i], 2, 0 );
-			vertex[m_count++] = byte3( x+1, height[i], y+1 ); material[mcount++] = byte3( map[i], 2, 0 );
-
-			vertex[m_count++] = byte3( x+1, height[i], y+1 ); material[mcount++] = byte3( map[i], 2, 0 );
-			vertex[m_count++] = byte3( x+1, height[i], y );   material[mcount++] = byte3( map[i], 2, 0 );
-			vertex[m_count++] = byte3( x,   height[i], y );   material[mcount++] = byte3( map[i], 2, 0 );
+			vtx.emplace_back( x,   height[i], y   ); 
+			vtx.emplace_back( x,   height[i], y+1 ); 
+			vtx.emplace_back( x+1, height[i], y+1 ); 
+			vtx.emplace_back( x+1, height[i], y+1 ); 
+			vtx.emplace_back( x+1, height[i], y );   
+			vtx.emplace_back( x,   height[i], y );   
+			mat.insert( mat.end(), 6, nv::i8vec3( map[i], 2, 0 ) );
 
 			if (i > 0 && height[i-1] != height[i])
@@ -147,11 +145,12 @@
 				for ( int h = height[i-1]; h != height[i]; h = h + dir )
 				{
-					vertex[m_count++] = byte3( x, h,     y );   material[mcount++] = byte3( m, -dir, 0 );
-					vertex[m_count++] = byte3( x, h,     y+1 ); material[mcount++] = byte3( m, -dir, 0 );
-					vertex[m_count++] = byte3( x, h+dir, y+1 ); material[mcount++] = byte3( m, -dir, 0 );
-
-					vertex[m_count++] = byte3( x, h+dir, y+1 ); material[mcount++] = byte3( m, -dir, 0 );
-					vertex[m_count++] = byte3( x, h+dir, y );   material[mcount++] = byte3( m, -dir, 0 );
-					vertex[m_count++] = byte3( x, h,     y );   material[mcount++] = byte3( m, -dir, 0 );
+					m_count += 6;
+					vtx.emplace_back( x, h,     y );   
+					vtx.emplace_back( x, h,     y+1 ); 
+					vtx.emplace_back( x, h+dir, y+1 ); 
+					vtx.emplace_back( x, h+dir, y+1 ); 
+					vtx.emplace_back( x, h+dir, y );   
+					vtx.emplace_back( x, h,     y );   
+					mat.insert( mat.end(), 6, nv::i8vec3( m, -dir, 0 ) );
 				}
 			}
@@ -163,11 +162,12 @@
 				for ( int h = height[i-size_x]; h != height[i]; h = h + dir )
 				{
-					vertex[m_count++] = byte3( x,   h,     y ); material[mcount++] = byte3( m, -3*dir, 0 );
-					vertex[m_count++] = byte3( x,   h+dir, y ); material[mcount++] = byte3( m, -3*dir, 0 );
-					vertex[m_count++] = byte3( x+1, h+dir, y ); material[mcount++] = byte3( m, -3*dir, 0 );
-
-					vertex[m_count++] = byte3( x+1, h+dir, y ); material[mcount++] = byte3( m, -3*dir, 0 );
-					vertex[m_count++] = byte3( x+1, h,     y ); material[mcount++] = byte3( m, -3*dir, 0 );
-					vertex[m_count++] = byte3( x,   h,     y ); material[mcount++] = byte3( m, -3*dir, 0 );
+					vtx.emplace_back( x,   h,     y ); 
+					vtx.emplace_back( x,   h+dir, y ); 
+					vtx.emplace_back( x+1, h+dir, y ); 
+
+					vtx.emplace_back( x+1, h+dir, y ); 
+					vtx.emplace_back( x+1, h,     y ); 
+					vtx.emplace_back( x,   h,     y ); 
+					mat.insert( mat.end(), 6, nv::i8vec3( m, -3*dir, 0 ) );
 				}
 			}
@@ -175,5 +175,6 @@
 		}
 
-		if (!init_program( "box",  m_box_program, m_box_va, m_count, vertex, material ) ) return false;
+		m_count = vtx.size();
+		if (!init_program( "box",  m_box_program, m_box_va, &wmesh ) ) return false;
 	}
 
@@ -181,14 +182,15 @@
 }
 
-bool application::init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, int count, void* vertex, void* material )
+bool application::init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, nv::mesh* m )
 {
 	p  = m_device->create_program( nv::slurp( name+".vert" ), nv::slurp( name+".frag" ) );
 	va = m_device->create_vertex_array();
-
-	nv::vertex_buffer* vbcoords   = m_device->create_vertex_buffer( nv::STATIC_DRAW, count*sizeof(byte3), vertex );
-	va->add_vertex_buffer( p->get_attribute( "coords" )->get_location(), vbcoords, nv::BYTE, 3 );
-	nv::vertex_buffer* vbmaterial = m_device->create_vertex_buffer( nv::STATIC_DRAW, count*sizeof(byte3), material );
-	va->add_vertex_buffer( p->get_attribute( "material" )->get_location(), vbmaterial, nv::BYTE, 3 );
-
+	const nv::mesh::map& attrs = m->get_attributes();
+
+	for ( auto attr : attrs )
+	{
+		nv::vertex_buffer* vb = m_device->create_vertex_buffer( nv::STATIC_DRAW, attr.second->get_size(), attr.second->get_data() );
+		va->add_vertex_buffer( p->get_attribute( attr.first )->get_location(), vb, attr.second->get_base_type(), attr.second->get_components() );
+	}
 	return true;
 }
