Index: trunk/nv/gfx/cached_buffer.hh
===================================================================
--- trunk/nv/gfx/cached_buffer.hh	(revision 118)
+++ trunk/nv/gfx/cached_buffer.hh	(revision 119)
@@ -16,4 +16,5 @@
 namespace nv
 {
+
 	template< typename T > class cached_buffer;
 
@@ -30,10 +31,35 @@
 			m_cache->reset();
 		}
-		void commit()
-		{
-			m_cache->commit( this );
+		bool commit( bool force_changed = false )
+		{
+			bool resized = force_changed || ( m_cached_size != m_data.size() );
+			bool result  = m_cache->commit( m_data, m_locked, resized, m_offset );
 			m_cached_size = m_data.size();
 			m_locked      = false;
-		}
+			return result;
+		}
+		
+		template < typename V >
+		bool commit_offset( bool force_changed, V value )
+		{
+			bool locked = m_locked;
+			bool result = commit( force_changed );
+			if ( locked || result )
+			{
+				m_cache->add_offset<T>( m_data.size(), m_offset, static_cast<T>(value) );
+			}
+			return result;
+		}
+
+		bool is_locked() const
+		{
+			return m_locked;
+		}
+
+		size_t get_offset() const
+		{
+			return m_offset;
+		}
+
 		vector& lock()
 		{
@@ -49,7 +75,5 @@
 			m_cache->reset();
 		}
-	private:
-		friend class cached_buffer<T>;
-
+	public:
 		vector m_data;
 		cache* m_cache;
@@ -63,10 +87,9 @@
 	{
 	public:
-		typedef buffer_slice<T> slice;
 		typedef std::vector<T>  vector;
 		typedef T               value_type;
-		static const int value_type_size = sizeof(T);
-
-		cached_buffer( device* dev, buffer_hint hint, int initial_size, bool is_vertex = true ) 
+		static const size_t value_type_size = sizeof(T);
+
+		cached_buffer( device* dev, buffer_hint hint, size_t initial_size, bool is_vertex = true ) 
 			: m_device( dev )
 			, m_buffer( nullptr )
@@ -81,28 +104,35 @@
 		}
 
-		void commit( slice* bslice )
-		{
+		bool commit( const vector& bv, bool updated, bool resized, size_t& offset )
+		{
+			if ( !m_full_update && resized )
+			{
+				m_data.erase( m_data.begin() + offset, m_data.end() );
+				m_min = glm::min<int>( m_min, offset );
+				m_full_update = true;
+			}
 			if ( m_full_update )
 			{
-				const vector& bv = bslice->data();
-				bslice->m_offset = m_data.size();
+				offset = m_data.size();
 				m_data.insert( m_data.end(), bv.cbegin(), bv.cend() );
 			}
-			else if ( bslice->m_locked )
-			{
-				const vector& bv = bslice->data();
-				if ( bslice->m_cached_size != bv.size() ) 
-				{
-					m_data.erase( m_data.begin() + bslice->m_offset, m_data.end() );
-					m_full_update = true;
-					m_data.insert( m_data.end(), bv.cbegin(), bv.cend() );
-					m_min = glm::min<int>( m_min, bslice->m_offset );
-				}
-				else
-				{
-					std::copy( bv.cbegin(), bv.cend(), m_data.begin() + bslice->m_offset );
-					m_min = glm::min<int>( m_min, bslice->m_offset );
-					m_max = glm::max<int>( m_max, bslice->m_offset + bv.size() );
-				}
+			else if ( updated )
+			{
+				std::copy( bv.cbegin(), bv.cend(), m_data.begin() + offset );
+				m_min = glm::min<size_t>( m_min, offset );
+				m_max = glm::max<size_t>( m_max, offset + bv.size() );
+			}
+			return m_full_update;
+		}
+
+		template < typename V > 
+		void add_offset( size_t size, size_t offset, V value )
+		{
+			if ( size == 0 ) return;
+			T* ptr  = m_data.data() + offset;
+			T* pend = ptr + size;
+			for ( ; ptr != pend; ptr++ )
+			{
+				*ptr += value;
 			}
 		}
@@ -128,27 +158,16 @@
 				create_buffer( bsize );
 				m_full_update = true;
+				m_min  = 0;
 				result = true;
 			}
-			m_buffer->bind();
-			if ( m_full_update )
-			{
-				if ( m_min > 0 )
-				{
-					int offset = m_min * value_type_size;
-					int size   = m_data.size() * value_type_size - offset;
-					m_buffer->update( m_data.data() + m_min, offset, size );
-				}
-				else
-				{
-					m_buffer->update( m_data.data(), 0, m_data.size() * value_type_size );
-				}
-			}
-			else if ( m_max > 0 )
-			{
+			if ( m_full_update ) m_max = m_data.size();
+			if ( m_max > 0 )
+			{
+				m_buffer->bind();
 				int offset = m_min * value_type_size;
 				int size   = (m_max-m_min) * value_type_size;
 				m_buffer->update( m_data.data() + m_min, offset, size );
-			}
-			m_buffer->unbind();
+				m_buffer->unbind();
+			}
 			m_full_update = false;
 			m_min = get_max_size();
@@ -193,8 +212,98 @@
 		vector      m_data;
 
-		int         m_min;
-		int         m_max;
+		size_t      m_min;
+		size_t      m_max;
 	};
 
+	template< typename T, typename I = uint16 > class indexed_cached_buffer;
+
+	template< typename T, typename I = uint16 >
+	class indexed_buffer_slice
+	{
+	public:
+		typedef indexed_cached_buffer<T,I> cache;
+		typedef buffer_slice<T> vertex_slice;
+		typedef buffer_slice<I> index_slice;
+		typedef typename vertex_slice::vector vertex_vector;
+		typedef typename index_slice::vector  index_vector;
+
+		indexed_buffer_slice( cache* c )
+			: m_vertex_slice( &c->get_vertex_cache() )
+			, m_index_slice( &c->get_index_cache() )
+			, m_cache( c )
+		{
+		}
+
+		void commit()
+		{
+			bool changed = m_vertex_slice.commit();
+			m_index_slice.commit_offset( changed, m_vertex_slice.get_offset() );
+		}
+		vertex_vector& lock_vertices()
+		{
+			return m_vertex_slice.lock();
+		}
+		index_vector& lock_indices()
+		{
+			return m_index_slice.lock();
+		}
+		const vertex_vector& vertex_data() 
+		{ 
+			return m_vertex_slice.data();
+		}
+		const index_vector& index_data() 
+		{ 
+			return m_index_slice.data();
+		}
+
+	private:
+		vertex_slice m_vertex_slice;
+		index_slice  m_index_slice;
+		cache*       m_cache;
+	};
+
+	template< typename T, typename I >
+	class indexed_cached_buffer
+	{
+	public:
+		typedef cached_buffer<T> cached_vertex_buffer;
+		typedef cached_buffer<I> cached_index_buffer;
+		static const int value_type_size = sizeof(T);
+
+		indexed_cached_buffer( device* dev, buffer_hint hint, int initial_size, int initial_index_size )
+			: m_vertex_buffer( dev, hint, initial_size, true )
+			, m_index_buffer( dev, hint, initial_index_size, false )
+		{
+
+		}
+
+		void reset()
+		{
+			m_vertex_buffer.reset();
+			m_index_buffer.reset();
+		}
+
+		bool commit()
+		{
+			bool vresult = m_vertex_buffer.commit();
+			bool iresult = m_index_buffer.commit();
+			return vresult || iresult;
+		}
+
+		int get_max_vertex_size() const { return m_vertex_buffer.get_max_size(); }
+		int get_max_index_size()  const { return m_index_buffer.get_max_size(); }
+		int get_vertex_size()     const { return m_vertex_buffer.get_size(); }
+		int get_index_size()      const { return m_index_buffer.get_size(); }
+		vertex_buffer* get_vertex_buffer() { return static_cast<vertex_buffer*>( m_vertex_buffer.get_buffer() ); }
+		index_buffer*  get_index_buffer()  { return static_cast<index_buffer*>( m_index_buffer.get_buffer() ); }
+		cached_vertex_buffer& get_vertex_cache() { return m_vertex_buffer; }
+		cached_index_buffer&  get_index_cache()  { return m_index_buffer; }
+
+	private:
+		cached_vertex_buffer m_vertex_buffer;
+		cached_index_buffer  m_index_buffer;
+	};
+
+
 } // namespace nv
 
Index: trunk/nv/interface/vertex_buffer.hh
===================================================================
--- trunk/nv/interface/vertex_buffer.hh	(revision 118)
+++ trunk/nv/interface/vertex_buffer.hh	(revision 119)
@@ -93,5 +93,5 @@
 	{
 	public:
-		vertex_array() : m_map(), m_index( nullptr ), m_index_owner( false ), m_index_type(INT) {}
+		vertex_array() : m_map(), m_index( nullptr ), m_index_owner( false ), m_index_type(USHORT) {}
 		void add_vertex_buffer( int location, vertex_buffer* buffer, datatype datatype, int components, int offset = 0, int stride = 0, bool owner = true ) 
 		{
@@ -109,7 +109,13 @@
 		void set_index_buffer( index_buffer* buffer, datatype datatype, bool owner ) 
 		{ 
+			if (m_index && m_index_owner) delete m_index; 
 			m_index       = buffer; 
 			m_index_owner = owner; 
 			m_index_type  = datatype;
+		}
+		void set_index_buffer( index_buffer* buffer ) 
+		{ 
+			if (m_index && m_index_owner) delete m_index; 
+			m_index       = buffer; 
 		}
 		bool has_index_buffer() const { return m_index != nullptr; }
Index: trunk/tests/cachebuf_test/nv_cachebuf_test.cc
===================================================================
--- trunk/tests/cachebuf_test/nv_cachebuf_test.cc	(revision 118)
+++ trunk/tests/cachebuf_test/nv_cachebuf_test.cc	(revision 119)
@@ -19,4 +19,6 @@
 #include <nv/gfx/cached_buffer.hh>
 
+#define INDEXED_TEST
+
 struct vertex
 {
@@ -28,4 +30,5 @@
 };
 
+#ifndef INDEXED_TEST
 struct quad
 {
@@ -63,9 +66,18 @@
 
 };
+#endif 
+
+#ifdef INDEXED_TEST
+typedef nv::indexed_cached_buffer<vertex> gcache;
+typedef nv::indexed_buffer_slice<vertex> gslice;
+#else
+typedef nv::cached_buffer<quad> gcache;
+typedef nv::buffer_slice<quad> gslice;
+#endif
 
 struct app_window
 {
-	app_window( nv::cached_buffer<quad>* cache, const glm::ivec2& a, const glm::ivec2& b, const glm::vec4& color )
-		: m_slice( cache ), m_a( a ), m_b( b ), m_c( color )
+	app_window( gcache* cache, const glm::ivec2& a, const glm::ivec2& b, const glm::vec4& color )
+		: m_slice( cache ), m_simple( false ), m_a( a ), m_b( b ), m_c( color )
 	{
 		create_complex();
@@ -76,16 +88,28 @@
 		m_c = color;
 		glm::vec4 dcolor( color.x * 0.5, color.y * 0.5, color.z * 0.5, 1.0 );
+		#ifdef INDEXED_TEST
+		std::vector<vertex>& v = m_slice.lock_vertices();
+		size_t size   = v.size();
+		size_t dcount = 8;
+		size_t dmin   = 8;
+		size_t count  = size;
+		#else
 		std::vector<quad>& v = m_slice.lock();
+		size_t size   = v.size();
+		size_t dcount = (size - 1) * 6;
+		size_t dmin   = 1;
+		size_t count  = size * 6;
+		#endif
 		vertex* vtx = (vertex*)v.data();
-		if ( v.size() > 1 )
-		{
-			for (size_t i = 0; i < (v.size() - 1) * 6; ++i )
+		if ( size > dmin )
+		{
+			for (size_t i = 0; i < dcount; ++i )
 				vtx[i].color = dcolor;
-			for (size_t i = (v.size() - 1) * 6; i < (v.size()) * 6; ++i )
+			for (size_t i = dcount; i < count; ++i )
 				vtx[i].color = color;
 		}
 		else
 		{
-			for (size_t i = 0; i < 6; ++i )
+			for (size_t i = 0; i < count; ++i )
 				vtx[i].color = color;
 		}
@@ -94,5 +118,5 @@
 	void simplify_toggle()
 	{
-		if ( m_slice.data().size() > 1 )
+		if ( !m_simple )
 		{
 			NV_LOG( nv::LOG_INFO, "Simplifing" );
@@ -108,7 +132,21 @@
 	void create_simple()
 	{
+		#ifdef INDEXED_TEST
+		std::vector<vertex>& v     = m_slice.lock_vertices();
+		std::vector<nv::uint16>& i = m_slice.lock_indices();
+		v.clear();
+		i.clear();
+		v.emplace_back( m_a, m_c );
+		v.emplace_back( nv::ivec2( m_a.x, m_b.y ), m_c );
+		v.emplace_back( m_b, m_c );
+		v.emplace_back( nv::ivec2( m_b.x, m_a.y ), m_c );
+		nv::uint16 tmp[] = { 0, 1, 2, 2, 3, 0 };
+		i.insert( i.end(), tmp, std::end( tmp ) );
+		#else
 		std::vector<quad>& v = m_slice.lock();
 		v.clear();
 		v.emplace_back( m_a, m_b, m_c );
+		#endif
+		m_simple = true;
 	}
 
@@ -116,10 +154,40 @@
 	{
 		glm::vec4 dcolor( m_c.x * 0.5, m_c.y * 0.5, m_c.z * 0.5, 1.0 );
-		std::vector<quad>& v = m_slice.lock();
-		v.clear();
 		nv::ivec2 a2( m_a.x, m_b.y );
 		nv::ivec2 b2( m_b.x, m_a.y );
 		nv::ivec2 t1( 10, 10 );
 		nv::ivec2 t2( -10, 10 );
+		#ifdef INDEXED_TEST
+		std::vector<vertex>& v     = m_slice.lock_vertices();
+		std::vector<nv::uint16>& i = m_slice.lock_indices();
+		v.clear();
+		i.clear();
+		v.emplace_back( m_a- t1, dcolor ); // 0
+		v.emplace_back( a2 + t2, dcolor ); // 1
+		v.emplace_back( m_b+ t1, dcolor ); // 2
+		v.emplace_back( b2 - t2, dcolor ); // 3
+
+		v.emplace_back( m_a, dcolor ); // 4
+		v.emplace_back( a2, dcolor );  // 5
+		v.emplace_back( m_b, dcolor ); // 6
+		v.emplace_back( b2, dcolor );  // 7
+		nv::uint16 tmp[] = { 
+			0, 4, 7, 7, 3, 0,
+			0, 1, 5, 5, 4, 0,
+			1, 2, 6, 6, 5, 1,
+			2, 3, 7, 7, 6, 2,
+		};
+		i.insert( i.end(), tmp, std::end( tmp ) );
+
+		v.emplace_back( m_a, m_c );    // 8
+		v.emplace_back( a2, m_c );     // 9
+		v.emplace_back( m_b, m_c );    // 10
+		v.emplace_back( b2, m_c );     // 11
+		nv::uint16 tmp2[] = { 8, 9, 10, 10, 11, 8 };
+		i.insert( i.end(), tmp2, std::end( tmp2 ) );
+
+		#else
+		std::vector<quad>& v = m_slice.lock();
+		v.clear();
 		v.emplace_back( m_a - t1, m_a,       b2, b2 - t2, dcolor );
 		v.emplace_back( m_a - t1, a2 + t2, a2, m_a,       dcolor );
@@ -127,4 +195,6 @@
 		v.emplace_back( m_b + t1, b2 - t2, b2, m_b, dcolor );
 		v.emplace_back( m_a, m_b, m_c );
+		#endif
+		m_simple = false;
 	}
 
@@ -134,5 +204,6 @@
 	}
 
-	nv::buffer_slice<quad> m_slice;
+	gslice m_slice;
+	bool m_simple;
 	nv::ivec2 m_a;
 	nv::ivec2 m_b;
@@ -157,5 +228,5 @@
 	nv::render_state m_render_state;
 	
-	nv::cached_buffer<quad>* m_quad_cache;
+	gcache* m_quad_cache;
 	std::vector<app_window>  m_windows;
 
@@ -185,13 +256,20 @@
 {
 	{ 
-		m_program = m_device->create_program( nv::slurp( "cachebuf.vert" ), nv::slurp( "cachebuf.frag" ) );
-		m_va      = m_device->create_vertex_array();
-
-		m_quad_cache = new nv::cached_buffer<quad>( m_device, nv::DYNAMIC_DRAW, 20, true );
-		m_coord_loc  = m_program->get_attribute("coord")->get_location();
-		m_color_loc  = m_program->get_attribute("color")->get_location();
-
-		m_va->add_vertex_buffer( m_coord_loc, (nv::vertex_buffer*)m_quad_cache->get_buffer(), nv::INT,   2, 0, sizeof( vertex ), false );
-		m_va->add_vertex_buffer( m_color_loc, (nv::vertex_buffer*)m_quad_cache->get_buffer(), nv::FLOAT, 4, offset_of( &vertex::color ), sizeof( vertex ), false );
+		m_program   = m_device->create_program( nv::slurp( "cachebuf.vert" ), nv::slurp( "cachebuf.frag" ) );
+		m_coord_loc = m_program->get_attribute("coord")->get_location();
+		m_color_loc = m_program->get_attribute("color")->get_location();
+		m_va        = m_device->create_vertex_array();
+
+		#ifdef INDEXED_TEST
+		m_quad_cache = new gcache( m_device, nv::DYNAMIC_DRAW, 200, 200 );
+		m_va->set_index_buffer( m_quad_cache->get_index_buffer(), nv::USHORT, false );
+		nv::vertex_buffer* buffer = m_quad_cache->get_vertex_buffer();
+		#else
+		m_quad_cache = new gcache( m_device, nv::DYNAMIC_DRAW, 20, true );
+		nv::vertex_buffer* buffer = (nv::vertex_buffer*)m_quad_cache->get_buffer();
+		#endif
+
+		m_va->add_vertex_buffer( m_coord_loc, buffer, nv::INT,   2, 0, sizeof( vertex ), false );
+		m_va->add_vertex_buffer( m_color_loc, buffer, nv::FLOAT, 4, offset_of( &vertex::color ), sizeof( vertex ), false );
 	}
 	return true;
@@ -213,6 +291,12 @@
 		if (m_quad_cache->commit() )
 		{
-			m_va->update_vertex_buffer( m_coord_loc, (nv::vertex_buffer*)m_quad_cache->get_buffer(), false );
-			m_va->update_vertex_buffer( m_color_loc, (nv::vertex_buffer*)m_quad_cache->get_buffer(), false );
+			#ifdef INDEXED_TEST
+			m_va->set_index_buffer( m_quad_cache->get_index_buffer() );
+			nv::vertex_buffer* buffer = m_quad_cache->get_vertex_buffer();
+			#else
+			nv::vertex_buffer* buffer = (nv::vertex_buffer*)m_quad_cache->get_buffer();
+			#endif
+			m_va->update_vertex_buffer( m_coord_loc, buffer, false );
+			m_va->update_vertex_buffer( m_color_loc, buffer, false );
 		}
 
@@ -220,5 +304,10 @@
 		m_program->bind();
 //		m_program->set_uniform( "tex", 0 );
-		m_window->get_context()->draw( nv::TRIANGLES, m_render_state, m_program, m_va, m_quad_cache->get_size() * 6 );
+		#ifdef INDEXED_TEST
+		size_t draw_size = m_quad_cache->get_index_size();
+		#else
+		size_t draw_size = m_quad_cache->get_size() * 6;
+		#endif
+		m_window->get_context()->draw( nv::TRIANGLES, m_render_state, m_program, m_va, draw_size );
 		m_window->swap_buffers();
 
