Index: trunk/nv/interface/device.hh
===================================================================
--- trunk/nv/interface/device.hh	(revision 72)
+++ trunk/nv/interface/device.hh	(revision 73)
@@ -15,4 +15,5 @@
 #include <nv/common.hh>
 #include <nv/string.hh>
+#include <nv/interface/mesh.hh>
 #include <nv/interface/vertex_buffer.hh>
 #include <nv/interface/texture2d.hh>
@@ -32,4 +33,22 @@
 		virtual vertex_array* create_vertex_array() = 0;
 		virtual texture2d* create_texture2d( ivec2 size, image_format aformat, datatype adatatype, sampler asampler, void* data = nullptr ) = 0;
+
+		virtual vertex_array* create_vertex_array( const mesh* 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 );
+			}
+			return result;
+		}
 	};
 
Index: trunk/nv/interface/mesh.hh
===================================================================
--- trunk/nv/interface/mesh.hh	(revision 72)
+++ trunk/nv/interface/mesh.hh	(revision 73)
@@ -17,4 +17,5 @@
 #include <nv/string.hh>
 #include <nv/types.hh>
+#include <nv/interface/context.hh>
 #include <unordered_map>
 #include <vector>
@@ -100,8 +101,9 @@
 		}
 
+		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( const string& attr )
+		vertex_attribute<T>* get_indices() 
 		{
 			return m_indices->get_type() == type_to_enum<T>() ? ((vertex_attribute<T>*)(m_indices)); : nullptr; 
Index: trunk/nv/interface/program.hh
===================================================================
--- trunk/nv/interface/program.hh	(revision 72)
+++ trunk/nv/interface/program.hh	(revision 73)
@@ -98,4 +98,8 @@
 					i != m_uniform_map.end(); ++i ) delete i->second;
 		}
+
+		const attribute_map& get_attributes() const { return m_attribute_map; }
+		const uniform_map& get_uniforms() const { return m_uniform_map; }
+
 		attribute* try_get_attribute( const string& name ) const
 		{
Index: trunk/tests/render_test/rl.cc
===================================================================
--- trunk/tests/render_test/rl.cc	(revision 72)
+++ trunk/tests/render_test/rl.cc	(revision 73)
@@ -66,5 +66,4 @@
 	application();
 	bool initialize();
-	bool init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, nv::mesh* m );
 	bool run();
 	~application();
@@ -117,6 +116,6 @@
 		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;
+		m_char_program = m_device->create_program( nv::slurp( "char.vert" ), nv::slurp( "char.frag" ) );
+		m_char_va      = m_device->create_vertex_array( &cmesh, &(m_char_program->get_attributes()), nv::STATIC_DRAW );
 	}
 
@@ -175,22 +174,9 @@
 		}
 
-		m_count = vtx.size();
-		if (!init_program( "box",  m_box_program, m_box_va, &wmesh ) ) return false;
-	}
-
-	return true;
-}
-
-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();
-	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() );
-	}
+		m_count       = vtx.size();
+		m_box_program = m_device->create_program( nv::slurp( "box.vert" ), nv::slurp( "box.frag" ) );
+		m_box_va      = m_device->create_vertex_array( &wmesh, &(m_box_program->get_attributes()), nv::STATIC_DRAW );
+	}
+
 	return true;
 }
