Index: /trunk/nv/gl/gl_context.hh
===================================================================
--- /trunk/nv/gl/gl_context.hh	(revision 300)
+++ /trunk/nv/gl/gl_context.hh	(revision 301)
@@ -23,5 +23,5 @@
 	public:
 		~gl_context();
-		virtual void bind( texture2d* texture, texture_slot slot );
+		virtual void bind( texture t, texture_slot slot );
 		virtual void bind( program* p );
 		virtual void bind( vertex_buffer* b );
@@ -33,5 +33,5 @@
 		virtual void unbind( vertex_array* va );
 
-		virtual void update( texture2d* texture, void* data );
+		virtual void update( texture t, void* data );
 		virtual void update( index_buffer* b, const void* data, size_t offset, size_t size );
 		virtual void update( vertex_buffer* b, const void* data, size_t offset, size_t size );
Index: /trunk/nv/gl/gl_device.hh
===================================================================
--- /trunk/nv/gl/gl_device.hh	(revision 300)
+++ /trunk/nv/gl/gl_device.hh	(revision 301)
@@ -17,4 +17,9 @@
 namespace nv
 {
+	struct gl_texture_info : public texture_info
+	{
+		unsigned glid;
+	};
+
 	class gl_device : public device
 	{
@@ -28,10 +33,15 @@
 		virtual vertex_array* create_vertex_array();
 		virtual image_data* create_image_data( const std::string& filename ); // temporary
-		virtual texture2d* create_texture2d( ivec2 size, pixel_format aformat, datatype adatatype, sampler asampler, void* data = nullptr );
 		virtual uint32 get_ticks();
 		virtual void delay( uint32 ms );
+
+		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr );
+		virtual void release_texture( texture t );
+		virtual const texture_info* get_texture_info( texture t );
+
 		virtual ~gl_device();
 	private:
 		const void* m_info;
+		entity_store< gl_texture_info, texture > m_textures;
 	};
 
Index: /trunk/nv/gl/gl_enum.hh
===================================================================
--- /trunk/nv/gl/gl_enum.hh	(revision 300)
+++ /trunk/nv/gl/gl_enum.hh	(revision 301)
@@ -17,5 +17,5 @@
 #include <nv/interface/render_state.hh>
 #include <nv/interface/vertex_buffer.hh>
-#include <nv/interface/texture2d.hh>
+#include <nv/interface/image_data.hh>
 #include <nv/interface/context.hh>
 
Index: unk/nv/gl/gl_texture2d.hh
===================================================================
--- /trunk/nv/gl/gl_texture2d.hh	(revision 300)
+++ 	(revision )
@@ -1,33 +1,0 @@
-// 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 gl_texture2d.hh
- * @author Kornel Kisielewicz epyon@chaosforge.org
- * @brief Texture2D class
- */
-
-#ifndef NV_GL_TEXTURE2D_HH
-#define NV_GL_TEXTURE2D_HH
-
-#include <nv/interface/texture2d.hh>
-
-namespace nv
-{
-
-	class gl_texture2d : public texture2d
-	{
-	public:
-		friend class gl_context;
-
-		gl_texture2d( ivec2 size, pixel_format aformat, datatype adatatype, sampler asampler, void* data = nullptr );
-		~gl_texture2d();
-	protected:
-		unsigned glid;
-	};
-	
-} // namespace nv
-
-#endif // NV_GL_TEXTURE2D_HH
Index: /trunk/nv/interface/context.hh
===================================================================
--- /trunk/nv/interface/context.hh	(revision 300)
+++ /trunk/nv/interface/context.hh	(revision 301)
@@ -14,4 +14,5 @@
 
 #include <nv/common.hh>
+#include <nv/interface/device.hh>
 #include <nv/interface/camera.hh>
 #include <nv/interface/program.hh>
@@ -59,5 +60,5 @@
 			m_device = a_device; 
 		}
-		virtual void bind( texture2d*, texture_slot ) = 0;
+		virtual void bind( texture, texture_slot ) = 0;
 		virtual void bind( vertex_buffer* ) = 0;
 		virtual void bind( index_buffer* ) = 0;
@@ -68,5 +69,5 @@
 		virtual void unbind( program* ) = 0;
 		virtual void unbind( vertex_array* ) = 0;
-		virtual void update( texture2d*, void* ) = 0;
+		virtual void update( texture, void* ) = 0;
 		virtual void update( index_buffer*, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
 		virtual void update( vertex_buffer*, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
Index: /trunk/nv/interface/device.hh
===================================================================
--- /trunk/nv/interface/device.hh	(revision 300)
+++ /trunk/nv/interface/device.hh	(revision 301)
@@ -15,7 +15,7 @@
 #include <nv/common.hh>
 #include <nv/string.hh>
+#include <nv/handle.hh>
 #include <nv/interface/mesh_data.hh>
 #include <nv/interface/vertex_buffer.hh>
-#include <nv/interface/texture2d.hh>
 #include <nv/interface/image_data.hh>
 
@@ -24,4 +24,47 @@
 	class window;
 	class program;
+
+	struct sampler
+	{
+		enum filter
+		{
+			LINEAR,
+			NEAREST,
+			NEAREST_MIPMAP_NEAREST,
+			LINEAR_MIPMAP_NEAREST,
+			NEAREST_MIPMAP_LINEAR,
+			LINEAR_MIPMAP_LINEAR
+		};
+		enum wrap
+		{
+			CLAMP_TO_EDGE,
+			CLAMP_TO_BORDER, 
+			MIRRORED_REPEAT, 
+			REPEAT
+		};
+
+		filter filter_min;
+		filter filter_max;
+		wrap wrap_s;
+		wrap wrap_t;
+
+		sampler() : filter_min( LINEAR ), filter_max( LINEAR ), wrap_s( REPEAT ), wrap_t( REPEAT ) {}
+		sampler( filter min, filter max, wrap s, wrap t )
+			: filter_min( min ), filter_max( max ), wrap_s( s ), wrap_t( t ) {}
+		sampler( filter f, wrap w )
+			: filter_min( f ), filter_max( f ), wrap_s( w ), wrap_t( w ) {}
+
+	};
+
+	struct texture_info
+	{
+		ivec2        size;
+		image_format format;
+		sampler      sampler;
+	};
+
+
+	struct texture_tag {};
+	typedef handle< uint32, 16, 16, texture_tag > texture;
 
 	class device
@@ -35,15 +78,13 @@
 		virtual vertex_array* create_vertex_array() = 0;
 		virtual image_data* create_image_data( const std::string& filename ) = 0; // temporary
-		virtual texture2d* create_texture2d( ivec2 size, pixel_format aformat, datatype adatatype, sampler asampler, void* data = nullptr ) = 0;
+		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr ) = 0;
+		virtual void release_texture( texture ) = 0;
+		virtual const texture_info* get_texture_info( texture ) = 0;
 		virtual uint32 get_ticks() = 0;
 		virtual void delay( uint32 ms ) = 0;
 
-		texture2d* create_texture2d( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr )
+		virtual texture create_texture( image_data* data, sampler asampler ) 
 		{
-			return create_texture2d( size, aformat.format, aformat.type, asampler, data );
-		}
-		virtual texture2d* create_texture2d( image_data* data, sampler asampler ) 
-		{
-			return create_texture2d( data->get_size(), data->get_format(), asampler, (void*)data->get_data() );
+			return create_texture( data->get_size(), data->get_format(), asampler, (void*)data->get_data() );
 		}
 
Index: unk/nv/interface/texture2d.hh
===================================================================
--- /trunk/nv/interface/texture2d.hh	(revision 300)
+++ 	(revision )
@@ -1,75 +1,0 @@
-// 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 texture2d.hh
- * @author Kornel Kisielewicz epyon@chaosforge.org
- * @brief Texture2D class
- */
-
-#ifndef NV_TEXTURE2D_HH
-#define NV_TEXTURE2D_HH
-
-#include <nv/common.hh>
-#include <nv/math.hh>
-#include <nv/interface/image_data.hh>
-
-namespace nv
-{
-
-	struct sampler
-	{
-		enum filter
-		{
-			LINEAR,
-			NEAREST,
-			NEAREST_MIPMAP_NEAREST,
-			LINEAR_MIPMAP_NEAREST,
-			NEAREST_MIPMAP_LINEAR,
-			LINEAR_MIPMAP_LINEAR
-		};
-		enum wrap
-		{
-			CLAMP_TO_EDGE,
-			CLAMP_TO_BORDER, 
-			MIRRORED_REPEAT, 
-			REPEAT
-		};
-
-		filter filter_min;
-		filter filter_max;
-		wrap wrap_s;
-		wrap wrap_t;
-
-		sampler( filter min, filter max, wrap s, wrap t )
-			: filter_min( min ), filter_max( max ), wrap_s( s ), wrap_t( t ) {}
-		sampler( filter f, wrap w )
-			: filter_min( f ), filter_max( f ), wrap_s( w ), wrap_t( w ) {}
-
-	};
-
-	class texture2d
-	{
-	protected:
-		texture2d( ivec2 size, pixel_format aformat, datatype adatatype, sampler asampler ) : 
-			m_size( size ), m_format( aformat, adatatype ), m_sampler( asampler ) {}
-	public:
-		const ivec2& get_size() const { return m_size; }
-		int get_width() const { return m_size.x; }
-		int get_height() const { return m_size.y; }
-		image_format get_format() const { return m_format; }
-		image_format get_pixel_format() const { return m_format.format; }
-		datatype get_type() const { return m_format.type; }
-		const sampler& get_sampler() const { return m_sampler; }
-		virtual ~texture2d() {}
-	protected:
-		ivec2        m_size;
-		image_format m_format;
-		sampler      m_sampler;
-	};
-
-} // namespace nv
-
-#endif // NV_TEXTURE2D_HH
Index: /trunk/src/gl/gl_context.cc
===================================================================
--- /trunk/src/gl/gl_context.cc	(revision 300)
+++ /trunk/src/gl/gl_context.cc	(revision 301)
@@ -8,5 +8,5 @@
 #include "nv/lib/gl.hh"
 #include "nv/lib/sdl.hh"
-#include "nv/gl/gl_texture2d.hh"
+#include "nv/gl/gl_device.hh"
 #include "nv/gl/gl_program.hh"
 #include "nv/gl/gl_vertex_buffer.hh"
@@ -14,9 +14,12 @@
 using namespace nv;
 
-void gl_context::bind( texture2d* texture, texture_slot slot )
-{
-	GLuint id = static_cast< gl_texture2d* >( texture )->glid;
-	glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
-	glBindTexture( GL_TEXTURE_2D, id );
+void gl_context::bind( texture t, texture_slot slot )
+{
+	const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
+	if ( info )
+	{
+		glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
+		glBindTexture( GL_TEXTURE_2D, info->glid );
+	}
 }
 
@@ -94,12 +97,15 @@
 }
 
-void gl_context::update( texture2d* texture, void* data )
-{
-	GLuint id = static_cast< gl_texture2d* >( texture )->glid;
-	image_format format = texture->get_format();
-	ivec2        size   = texture->get_size();
-
-	glBindTexture( GL_TEXTURE_2D, id );
-	glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_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( texture t, void* data )
+{
+	const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
+	if ( info )
+	{
+		image_format format = info->format;
+		ivec2        size   = info->size;
+
+		glBindTexture( GL_TEXTURE_2D, info->glid );
+		glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(format.format), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
+	}
 }
 
Index: /trunk/src/gl/gl_device.cc
===================================================================
--- /trunk/src/gl/gl_device.cc	(revision 300)
+++ /trunk/src/gl/gl_device.cc	(revision 301)
@@ -8,8 +8,9 @@
 #include "nv/gl/gl_program.hh"
 #include "nv/gl/gl_vertex_buffer.hh"
-#include "nv/gl/gl_texture2d.hh"
 #include "nv/logging.hh"
 #include "nv/lib/sdl.hh"
 #include "nv/lib/sdl_image.hh"
+#include "nv/gl/gl_enum.hh"
+#include "nv/lib/gl.hh"
 
 using namespace nv;
@@ -88,9 +89,4 @@
 }
 
-texture2d* gl_device::create_texture2d( ivec2 size, pixel_format aformat, datatype adatatype, sampler asampler, void* data /*= nullptr */ )
-{
-	return new gl_texture2d( size, aformat, adatatype, asampler, data );
-}
-
 uint32 gl_device::get_ticks()
 {
@@ -105,4 +101,58 @@
 gl_device::~gl_device()
 {
+	// TODO: better use release_texture
+	for ( auto& t : m_textures ) glDeleteTextures( 1, &t.glid );
+
 	SDL_Quit();
 }
+
+nv::texture nv::gl_device::create_texture( ivec2 size, image_format aformat, sampler asampler, void* data /*= nullptr */ )
+{
+	unsigned glid = 0;
+	glGenTextures( 1, &glid );
+
+	glBindTexture( GL_TEXTURE_2D, glid );
+
+	// Detect if mipmapping was requested
+	if (( asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST ) ||
+		( asampler.filter_max != sampler::LINEAR && asampler.filter_max != sampler::NEAREST ))
+	{
+		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+	}
+
+	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_min ) );
+	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_max ) );
+	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (int)nv::sampler_wrap_to_enum( asampler.wrap_s) );
+	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (int)nv::sampler_wrap_to_enum( asampler.wrap_t) );
+
+	if (data)
+	{
+		glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(aformat.format), size.x, size.y, 0, nv::image_format_to_enum(aformat.format), nv::datatype_to_gl_enum(aformat.type), data );
+	}
+
+	glBindTexture( GL_TEXTURE_2D, 0 );
+
+	texture result = m_textures.create();
+	gl_texture_info* info = m_textures.get( result );
+	info->format  = aformat;
+	info->sampler = asampler;
+	info->size    = size;
+	info->glid    = glid;
+	return result;
+}
+
+void nv::gl_device::release_texture( texture t )
+{
+	gl_texture_info* info = m_textures.get( t );
+	if ( info )
+	{
+		glDeleteTextures( 1, &(info->glid) );
+		m_textures.destroy( t );
+	}
+}
+
+const texture_info* nv::gl_device::get_texture_info( texture t )
+{
+	return m_textures.get( t );
+}
+
Index: unk/src/gl/gl_texture2d.cc
===================================================================
--- /trunk/src/gl/gl_texture2d.cc	(revision 300)
+++ 	(revision )
@@ -1,46 +1,0 @@
-// Copyright (C) 2012-2013 Kornel Kisielewicz
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-
-#include "nv/gl/gl_texture2d.hh"
-
-#include "nv/gl/gl_enum.hh"
-#include "nv/lib/gl.hh"
-
-using namespace nv;
-
-nv::gl_texture2d::gl_texture2d( ivec2 size, pixel_format aformat, datatype adatatype, sampler asampler, void* data /*= nullptr */ )
-	: texture2d( size, aformat, adatatype, asampler )
-{
-	glGenTextures( 1, &glid );
-
-	glBindTexture( GL_TEXTURE_2D, glid );
-
-	// Detect if mipmapping was requested
-	if (( asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST ) ||
-		( asampler.filter_max != sampler::LINEAR && asampler.filter_max != sampler::NEAREST ))
-	{
-		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
-	}
-
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (int)nv::sampler_filter_to_enum( m_sampler.filter_min ) );
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (int)nv::sampler_filter_to_enum( m_sampler.filter_max ) );
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (int)nv::sampler_wrap_to_enum( m_sampler.wrap_s) );
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (int)nv::sampler_wrap_to_enum( m_sampler.wrap_t) );
-
-	if (data)
-	{
-		glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(m_format.format), m_size.x, m_size.y, 0, nv::image_format_to_enum(m_format.format), nv::datatype_to_gl_enum(m_format.type), data );
-	}
-
-	glBindTexture( GL_TEXTURE_2D, 0 );
-}
-
-nv::gl_texture2d::~gl_texture2d()
-{
-	if ( glid != 0 )
-	{
-		glDeleteTextures( 1, &glid );
-	}
-}
-
Index: /trunk/src/gui/gui_renderer.cc
===================================================================
--- /trunk/src/gui/gui_renderer.cc	(revision 300)
+++ /trunk/src/gui/gui_renderer.cc	(revision 301)
@@ -65,6 +65,6 @@
 {
 public:
-	screen_render_data( context* ctx, size_t initial_size )
-		: buffer( ctx, nv::DYNAMIC_DRAW, initial_size ), varray( nullptr ), shader(nullptr), texture(nullptr) 
+	screen_render_data( context* actx, size_t initial_size )
+		: buffer( actx, nv::DYNAMIC_DRAW, initial_size ), varray( nullptr ), shader(nullptr)
 	{
 
@@ -74,11 +74,10 @@
 		delete shader; 
 		delete varray; 
-		delete texture;
 	}
 
 	nv::sliced_buffer<gui_quad> buffer;
+	nv::texture       tex;
 	nv::vertex_array* varray;
 	nv::program*      shader;
-	nv::texture2d*    texture;
 };
 
@@ -121,5 +120,5 @@
 
 	nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
-	sr->texture = m_window->get_device()->create_texture2d( m_atlas.get_size(), nv::RGBA, nv::UBYTE, sampler, nullptr );
+	sr->tex = m_window->get_device()->create_texture( m_atlas.get_size(), image_format( nv::RGBA, nv::UBYTE ), sampler, nullptr );
 
 	m_render_state.depth_test.enabled = false;
@@ -262,5 +261,5 @@
 	if ( m_reupload )
 	{
-		m_context->update( sr->texture, (void*)m_atlas.get_data() );
+		m_context->update( sr->tex, (void*)m_atlas.get_data() );
 		m_reupload = false;
 	}
@@ -273,5 +272,5 @@
 		sr->varray->update_vertex_buffer( nv::slot::COLOR,    vb, false );
 	}
-	m_context->bind( sr->texture, TEX_DIFFUSE );
+	m_context->bind( sr->tex, TEX_DIFFUSE );
 	m_context->draw( TRIANGLES, m_render_state, m_scene_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
 }
@@ -283,4 +282,8 @@
 		delete p;
 	}
-	delete m_render_data;
-}
+	if ( m_render_data )
+	{
+		m_context->get_device()->release_texture( ((screen_render_data*)m_render_data)->tex );
+		delete m_render_data;
+	}
+}
