Index: trunk/nv/base/rtti_support.hh
===================================================================
--- trunk/nv/base/rtti_support.hh	(revision 472)
+++ trunk/nv/base/rtti_support.hh	(revision 473)
@@ -17,24 +17,22 @@
 
 #define NV_RTTI_DECLARE(T) \
-namespace nv { \
-template<> struct rtti_type_hash< T > { \
+template<> struct ::nv::rtti_type_hash< T > { \
+NV_MSVC_SUPRESS( 4307 )\
+	static const nv::uint64 value = nv::rtti_const_hash(#T); \
 	static const char* name() { return #T; } \
 	static nv::uint64 hash() { \
-NV_MSVC_SUPRESS( 4307 )\
-		static const nv::uint64 value = nv::rtti_const_hash(#T); \
 		return value; \
 	} \
-};} \
+}; \
 
 #define NV_RTTI_DECLARE_NAME(T,NAME) \
-namespace nv { \
-template<> struct rtti_type_hash< T > { \
+template<> struct ::nv::rtti_type_hash< T > { \
+NV_MSVC_SUPRESS( 4307 )\
+	static const nv::uint64 value = nv::rtti_const_hash(#T); \
 	static const char* name() { return NAME; } \
 	static nv::uint64 hash() { \
-NV_MSVC_SUPRESS( 4307 )\
-		static const nv::uint64 value = nv::rtti_const_hash(#T); \
 		return value; \
 				} \
-};} \
+}; \
 
 namespace nv
Index: trunk/nv/core/arcball.hh
===================================================================
--- trunk/nv/core/arcball.hh	(revision 472)
+++ trunk/nv/core/arcball.hh	(revision 473)
@@ -50,5 +50,5 @@
 			vec3 vb = get_arcball_vector( nposition );
 
-			m_angle = math::acos( math::min( 1.0f, math::dot( va, vb ) ) );
+			m_angle = nv::acos( math::min( 1.0f, math::dot( va, vb ) ) );
 			m_axis  = math::cross( va, vb );
 			m_last  = nposition;
Index: trunk/nv/gl/gl_context.hh
===================================================================
--- trunk/nv/gl/gl_context.hh	(revision 472)
+++ trunk/nv/gl/gl_context.hh	(revision 473)
@@ -48,11 +48,13 @@
 		virtual void bind( framebuffer f, framebuffer_slot ft = FRAMEBUFFER );
 		virtual void bind( texture t, texture_slot slot );
+		virtual void bind( buffer b, uint32 index, size_t offset = 0, size_t size = 0 );
 
 		virtual void update( texture t, const void* data );
 		virtual void update( buffer b, const void* data, size_t offset, size_t size );
+		virtual void update( buffer b, uint32 index, const void* data, size_t offset, size_t size );
 
 		virtual void clear( const clear_state& cs );
 		// temporary
-		virtual void draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count );
+		virtual void draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count, size_t first = 0 );
 		virtual const ivec4& get_viewport();
 		virtual void set_viewport( const ivec4& viewport );
Index: trunk/nv/gl/gl_device.hh
===================================================================
--- trunk/nv/gl/gl_device.hh	(revision 472)
+++ trunk/nv/gl/gl_device.hh	(revision 473)
@@ -56,4 +56,5 @@
 
 		virtual int get_attribute_location( program p, const string_view& name, bool fatal = true ) const;
+		virtual int get_block_location( program p, const string_view& name, bool fatal = true ) const;
 		virtual void prepare_program( program p );
 		virtual string_view get_shader_header() const { return m_shader_header; }
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 472)
+++ trunk/nv/interface/context.hh	(revision 473)
@@ -102,15 +102,18 @@
 		virtual void bind( framebuffer f, framebuffer_slot slot = FRAMEBUFFER ) = 0;
 		virtual void bind( texture, texture_slot ) = 0;
+		virtual void bind( buffer, uint32 /*index*/, size_t /*offset*/ = 0, size_t /*size */= 0 ) = 0;
+
 		virtual void update( texture, const void* ) = 0;
 		virtual void update( buffer, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
+		virtual void update( buffer, uint32 /*index*/, const void* , size_t /*offset*/, size_t /*size*/ ) = 0;
 
 		virtual void clear( const clear_state& cs ) = 0;
 		// temporary
-		virtual void draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count ) = 0;
-
-		void draw( primitive prim, const render_state& rs, const scene_state& s, program p, vertex_array va, size_t count )
+		virtual void draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count, size_t first = 0 ) = 0;
+
+		void draw( primitive prim, const render_state& rs, const scene_state& s, program p, vertex_array va, size_t count, size_t first = 0 )
 		{
 			apply_engine_uniforms(p,s);
-			draw( prim, rs, p, va, count );
+			draw( prim, rs, p, va, count, first );
 		}
 		virtual void apply_engine_uniforms( program p, const scene_state& s ) = 0;
Index: trunk/nv/interface/device.hh
===================================================================
--- trunk/nv/interface/device.hh	(revision 472)
+++ trunk/nv/interface/device.hh	(revision 473)
@@ -82,7 +82,12 @@
 	struct buffer_tag {};
 	struct program_tag {};
+
 	typedef handle< uint32, 16, 16, buffer_tag >       buffer;
 	typedef handle< uint32, 16, 16, texture_tag >      texture;
 	typedef handle< uint32, 16, 16, program_tag >      program;
+
+	NV_RTTI_DECLARE_NAME( buffer,  "buffer" )
+	NV_RTTI_DECLARE_NAME( texture, "texture" )
+	NV_RTTI_DECLARE_NAME( program, "program" )
 
 	struct sampler
@@ -129,4 +134,5 @@
 		VERTEX_BUFFER,
 		INDEX_BUFFER,
+		UNIFORM_BUFFER,
 	};
 
@@ -198,5 +204,12 @@
 		}
 
+		int try_get_block_location( program p, const string_view& name ) const
+		{
+			return get_block_location( p, name, false );
+		}
+
 		virtual int get_attribute_location( program p, const string_view& name, bool fatal = true ) const = 0;
+		virtual int get_block_location( program p, const string_view& name, bool fatal = true ) const = 0;
+
 
 		template < typename T >
Index: trunk/nv/stl/string/short_string.hh
===================================================================
--- trunk/nv/stl/string/short_string.hh	(revision 472)
+++ trunk/nv/stl/string/short_string.hh	(revision 473)
@@ -145,5 +145,5 @@
 		{
 			Storage::reserve( new_size + 1 );
-			Storage::resize( min( new_size, capacity() - 1 ) );
+			Storage::resize( min( new_size, this->capacity() - 1 ) );
 			this->data()[this->size()] = 0;
 		}
@@ -172,6 +172,6 @@
 			else
 			{
-				result = capacity() - this->size() - 1;
-				Storage::try_resize( capacity() - 1, true, 1 );
+				result = this->capacity() - this->size() - 1;
+				Storage::try_resize( this->capacity() - 1, true, 1 );
 			}
 			this->data()[this->size()] = 0;
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 472)
+++ trunk/src/gl/gl_context.cc	(revision 473)
@@ -205,4 +205,16 @@
 	{
 		glBindFramebuffer( framebuffer_slot_to_enum(ft), 0 );
+	}
+}
+
+void nv::gl_context::bind( buffer b, uint32 index, size_t offset /*= 0*/, size_t size /*= 0 */ )
+{
+	const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
+	if ( info )
+	{
+		if ( size == 0 )
+			glBindBufferBase( buffer_type_to_enum( info->type ), index, info->glid );
+		else
+			glBindBufferRange( buffer_type_to_enum( info->type ), index, info->glid, offset, size );
 	}
 }
@@ -339,4 +351,18 @@
 		else
 			glTexImage2D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum(format.format) ), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
+	}
+}
+
+void nv::gl_context::update( buffer b, uint32 index, const void* data, size_t offset, size_t size )
+{
+	const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
+	if ( info )
+	{
+		GLenum glenum = buffer_type_to_enum( info->type );
+		if ( size == 0 )
+			glBindBufferBase( glenum, index, info->glid );
+		else
+			glBindBufferRange( glenum, index, info->glid, offset, size );
+		glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );
 	}
 }
@@ -750,5 +776,5 @@
 }
 
-void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, nv::size_t count )
+void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, nv::size_t count, nv::size_t first )
 {
 	apply_render_state( rs );
@@ -760,9 +786,9 @@
 		if ( info->index.is_valid() )
 		{
-			glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), 0 );
+			glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), reinterpret_cast< const void* >( get_datatype_info( info->index_type ).size * first ) );
 		}
 		else
 		{
-			glDrawArrays( primitive_to_enum(prim), 0, static_cast<GLsizei>( count ) );
+			glDrawArrays( primitive_to_enum(prim), first, static_cast<GLsizei>( count ) );
 		}
 		unbind( va );
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 472)
+++ trunk/src/gl/gl_device.cc	(revision 473)
@@ -337,4 +337,9 @@
 		}
 	}
+	return -1;
+}
+
+int nv::gl_device::get_block_location( program p, const string_view& name, bool fatal /*= true */ ) const
+{
 	return -1;
 }
@@ -450,5 +455,7 @@
 {
 	int params;
+	int bparams;
 	glGetProgramiv( p->glid, GL_ACTIVE_UNIFORMS, &params );
+	glGetProgramiv( p->glid, GL_ACTIVE_UNIFORM_BLOCKS, &bparams );
 
 	for ( unsigned i = 0; i < unsigned( params ); ++i )
@@ -479,4 +486,13 @@
 		NV_ASSERT( u, "Unknown uniform type!" );
 		(*p->m_uniform_map)[ name ] = u;
+	}
+
+	for ( unsigned i = 0; i < unsigned( bparams ); ++i )
+	{
+		int uni_len;
+		char name_buffer[128];
+
+		glGetActiveUniformBlockName( p->glid, i, 128, &uni_len, name_buffer );
+		NV_LOG_INFO( string_view( name_buffer, size_t( uni_len ) ) );
 	}
 }
Index: trunk/src/gl/gl_enum.cc
===================================================================
--- trunk/src/gl/gl_enum.cc	(revision 472)
+++ trunk/src/gl/gl_enum.cc	(revision 473)
@@ -168,6 +168,7 @@
 	switch( type )
 	{
-	case VERTEX_BUFFER : return GL_ARRAY_BUFFER;
-	case INDEX_BUFFER  : return GL_ELEMENT_ARRAY_BUFFER;
+	case VERTEX_BUFFER  : return GL_ARRAY_BUFFER;
+	case INDEX_BUFFER   : return GL_ELEMENT_ARRAY_BUFFER;
+	case UNIFORM_BUFFER : return GL_UNIFORM_BUFFER;
 		NV_RETURN_COVERED_DEFAULT( 0 );
 	}
