Index: trunk/nv/gfx/cached_buffer.hh
===================================================================
--- trunk/nv/gfx/cached_buffer.hh	(revision 100)
+++ trunk/nv/gfx/cached_buffer.hh	(revision 100)
@@ -0,0 +1,174 @@
+// 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
+
+// TODO : Force no resize on the buffer_slice!
+// TODO : Multiple update support?
+
+#ifndef NV_CACHED_BUFFER_HH
+#define NV_CACHED_BUFFER_HH
+
+#include <nv/common.hh>
+#include <nv/interface/vertex_buffer.hh>
+
+namespace nv
+{
+	template< typename T > class cached_buffer;
+
+	template< typename T >
+	class buffer_slice
+	{
+	public:
+		typedef cached_buffer<T> cache;
+		typedef std::vector<T>  vector;
+
+		buffer_slice( cache* c ) 
+			: m_cache( c ), m_offset( 0 ), m_locked( true )
+		{
+			m_cache->reset();
+		}
+		void commit()
+		{
+			m_cache->commit( this );
+			m_locked = false;
+		}
+		vector& lock()
+		{
+			m_locked = true;
+			return m_data;
+		}
+		const vector& data() 
+		{ 
+			return m_data; 
+		}
+		~buffer_slice()
+		{
+			m_cache->reset();
+		}
+	private:
+		friend class cached_buffer<T>;
+
+		vector m_data;
+		cache* m_cache;
+		size_t m_offset;
+		bool   m_locked;
+	};
+
+	template< typename T >
+	class cached_buffer
+	{
+	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 ) 
+			: m_device( dev )
+			, m_buffer( nullptr )
+			, m_hint( hint )
+			, m_full_update( true )
+			, m_is_vertex( is_vertex )
+			, m_data()
+			, m_min(0)
+			, m_max(0)
+		{ 
+			create_buffer( initial_size );
+		}
+
+		void commit( slice* bslice )
+		{
+			if ( m_full_update )
+			{
+				const vector& bv = bslice->data();
+				bslice.m_offset = m_data.size();
+				m_data.insert( m_data.end(), bv.cbegin(), bv.cend() );
+			}
+			else if ( bslice.m_locked )
+			{
+				const vector& bv = bslice->data();
+				std::copy( bv.cbegin(), bv.cend(), m_data.begin() + bslice->m_offset );
+				m_min = glm::min( m_min, bslice->m_offset );
+				m_max = glm::max( m_max, bslice->m_offset + bv.size() );
+			}
+		}
+
+		void reset()
+		{
+			m_data.clear();
+			m_full_update = true;
+			m_min = 0;
+			m_max = 0;
+		}
+
+		void commit()
+		{
+			int bsize = get_max_size();
+			if ( m_data.size() > bsize )
+			{
+				while( m_data.size() > bsize ) bsize *= 2;
+				create_buffer( bsize );
+				m_full_update = true;
+			}
+			m_buffer->bind();
+			if ( m_full_update )
+			{
+				m_buffer->update( m_data.data(), 0, m_data.size() * value_type_size );
+			}
+			else if ( m_max > 0 )
+			{
+				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_full_update = false;
+			m_min = get_max_size();
+			m_max = 0;
+		}
+
+		int get_max_size() const
+		{ 
+			return m_buffer->get_size() / value_type_size;
+		}
+
+		int get_size() const
+		{ 
+			return m_data.size(); 
+		}
+
+		buffer* get_buffer()
+		{ 
+			return m_buffer; 
+		}
+
+		virtual ~cached_buffer() 
+		{
+			delete m_buffer;
+		}
+	private:
+		void create_buffer( int size )
+		{
+			delete m_buffer;
+			if ( m_is_vertex )
+				m_buffer = m_device->create_vertex_buffer( m_hint, size * value_type_size, nullptr );
+			else
+				m_buffer = m_device->create_index_buffer( m_hint, size * value_type_size, nullptr );
+		}
+	private:
+		device*     m_device;
+		buffer*     m_buffer;
+		buffer_hint m_hint;
+		bool        m_full_update;
+		bool        m_is_vertex;
+		vector      m_data;
+
+		int         m_min;
+		int         m_max;
+	};
+
+} // namespace nv
+
+#endif // NV_CACHED_BUFFER_HH
Index: trunk/nv/gl/gl_vertex_buffer.hh
===================================================================
--- trunk/nv/gl/gl_vertex_buffer.hh	(revision 99)
+++ trunk/nv/gl/gl_vertex_buffer.hh	(revision 100)
@@ -23,6 +23,5 @@
 	public:
 		gl_vertex_buffer( buffer_hint hint, int size, void* data = nullptr );
-		virtual void assign( void* data );
-		virtual void assign( void* data, int offset, int size );
+		virtual void update( void* data, int offset, int size );
 		virtual void bind();
 		virtual void unbind();
@@ -36,6 +35,5 @@
 	public:
 		gl_index_buffer( buffer_hint hint, int size, void* data = nullptr );
-		virtual void assign( void* data );
-		virtual void assign( void* data, int offset, int size );
+		virtual void update( void* data, int offset, int size );
 		virtual void bind();
 		virtual void unbind();
Index: trunk/nv/interface/vertex_buffer.hh
===================================================================
--- trunk/nv/interface/vertex_buffer.hh	(revision 99)
+++ trunk/nv/interface/vertex_buffer.hh	(revision 100)
@@ -32,6 +32,5 @@
 	public:
 		buffer( buffer_hint hint, int size ) { m_size = size; m_hint = hint; }
-		virtual void assign( void* data ) = 0;
-		virtual void assign( void* data, int offset, int size ) = 0;
+		virtual void update( void* data, int offset, int size ) = 0;
 		virtual void bind() = 0;
 		virtual void unbind() = 0;
Index: trunk/src/gl/gl_vertex_buffer.cc
===================================================================
--- trunk/src/gl/gl_vertex_buffer.cc	(revision 99)
+++ trunk/src/gl/gl_vertex_buffer.cc	(revision 100)
@@ -13,22 +13,12 @@
 	: vertex_buffer( hint, size ), m_name()
 {
-	if (data)
-	{
-		assign( data );
-	}
+	bind();
+	glBufferData( GL_ARRAY_BUFFER, m_size, data, buffer_hint_to_enum( m_hint ) );
+	unbind();
 }
 
-void gl_vertex_buffer::assign( void* data )
+void gl_vertex_buffer::update( void* data, int offset, int size )
 {
-	glBindBuffer( GL_ARRAY_BUFFER, m_name.get_value() );
-	glBufferData( GL_ARRAY_BUFFER, m_size, data, buffer_hint_to_enum( m_hint ) );
-	glBindBuffer( GL_ARRAY_BUFFER, 0);
-}
-
-void gl_vertex_buffer::assign( void* data, int offset, int size )
-{
-	glBindBuffer( GL_ARRAY_BUFFER, m_name.get_value() );
 	glBufferSubData( GL_ARRAY_BUFFER, offset, size, data );
-	glBindBuffer( GL_ARRAY_BUFFER, 0);
 }
 
@@ -52,22 +42,12 @@
 	: index_buffer( hint, size ), m_name()
 {
-	if (data)
-	{
-		assign( data );
-	}
+	bind();
+	glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_size, data, buffer_hint_to_enum( m_hint ) );
+	unbind();
 }
 
-void gl_index_buffer::assign( void* data )
+void gl_index_buffer::update( void* data, int offset, int size )
 {
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_name.get_value() );
-	glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_size, data, buffer_hint_to_enum( m_hint ) );
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0);
-}
-
-void gl_index_buffer::assign( void* data, int offset, int size )
-{
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_name.get_value() );
 	glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, offset, size, data );
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0);
 }
 
