Index: trunk/src/gfx/gfx_terminal.cc
===================================================================
--- trunk/src/gfx/gfx_terminal.cc	(revision 514)
+++ trunk/src/gfx/gfx_terminal.cc	(revision 514)
@@ -0,0 +1,200 @@
+// Copyright (C) 2016-2016 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of Nova libraries. 
+// For conditions of distribution and use, see copying.txt file in root folder.
+
+#include "nv/gfx/gfx_terminal.hh"
+
+#include "nv/core/logging.hh"
+
+using namespace nv;
+
+static const char *nv_gfx_terminal_vs = R"(
+#version 330
+in vec2 nv_position;
+in vec2 nv_texcoord;
+out vec2 v_texcoord;
+void main(void)
+{
+	gl_Position = vec4(nv_position, 0.0, 1.0);
+	v_texcoord  = nv_texcoord;
+};
+)";
+static const char *nv_gfx_terminal_fs = R"(
+#version 330
+in  vec2 v_texcoord;
+out vec4 o_frag_color;
+
+uniform vec2 term_size;
+uniform vec2 dev_size;
+//uniform vec2 gylph_size;
+uniform sampler2D nv_t_diffuse;
+
+struct term_data
+{
+	uint fg;
+	uint bg;
+	uint gylph;
+	uint pad;
+};
+
+layout(std140) uniform terminal_block
+{
+	term_data term[80*50];
+};
+
+void main(void)
+{
+	vec2 coord   = v_texcoord * term_size;
+	ivec2 icoord = ivec2( coord );
+	vec2 tc      = coord - vec2( icoord );
+	tc.y = 1.0f - tc.y;
+
+	coord.y = term_size.y - coord.y;
+	
+	int index = int( coord.x ) + int( term_size.x ) * int( coord.y );
+	uint fg   = term[ index ].fg;
+	int gylph = int( term[ index ].gylph );
+	ivec2 gxy = ivec2( gylph % 16, gylph / 16 );
+	vec2 gpos = vec2( ( float(gxy.x) + tc.x ) / 16.0f, ( float(gxy.y) + tc.y ) / 16.0f );
+	vec4 tt   = texture( nv_t_diffuse, gpos );
+
+
+    vec4 color = vec4(
+        float( ( fg & uint(0x00FF0000) ) >> 16 ) / 255.0f,
+        float( ( fg & uint(0x0000FF00) ) >> 8 ) / 255.0f,
+        float(   fg & uint(0x000000FF) ) / 255.0f,
+        1.0 //fg & uint(0xFF000000)
+	);
+	o_frag_color = vec4( color.xyz * tt.xyz + vec3( 0.0, 0.2, 0.0 ) * ( 1.0 - tt.xyz ), 1.0 * tt.x );
+//	o_frag_color = vec4( fg, 0.0, 0.0, 1.0) ;
+}
+)";
+
+struct gfx_terminal_uniform_block
+{
+	uint32 fgcolor = 0;
+	uint32 bgcolor = 0;
+	uint32 gylph   = 0;
+	uint32 pad;
+
+	void set( term_color fg, term_color bg, char ch )
+	{
+		fgcolor = fg.get_argb32();
+		bgcolor = bg.get_argb32();
+		gylph   = uint32( ch );
+		NV_LOG_INFO( uint32( 
+			( fgcolor & uint32( 0x00FF0000 ) ) >> 16 ), "-", uint32( ( fgcolor & uint32( 0x0000FF00 ) ) >> 8 ),"-" , uint32( fgcolor & uint32( 0x000000FF ) ) );
+	}
+};
+
+struct nv::gfx_terminal_data
+{
+	gfx_terminal_uniform_block* data;
+	dimension                   size;
+	buffer                      buffer;
+
+	gfx_terminal_data( dimension dim )
+	{
+		size = dim;
+		data = new gfx_terminal_uniform_block[dim.x * dim.y];
+	}
+
+	gfx_terminal_uniform_block& operator[]( position p )
+	{
+		int index = size.x * p.y + p.x;
+		return data[index];
+	}
+
+	~gfx_terminal_data()
+	{
+		delete[] data;
+	}
+};
+
+gfx_terminal::gfx_terminal( context* ctx, texture t, dimension tsize, dimension psize )
+	: terminal( tsize ), m_context( ctx )
+{
+	m_data = new gfx_terminal_data( tsize );
+	
+	struct qvtx
+	{
+		vec2 position;
+		vec2 texcoord;
+	};
+
+	qvtx quad[] = {
+		qvtx{ vec2( -1.0f,-1.0f ), vec2( 0.0f, 0.0f ) },
+		qvtx{ vec2( 1.0f,-1.0f ),  vec2( 1.0f, 0.0f ) },
+		qvtx{ vec2( 1.0f,1.0f ),   vec2( 1.0f, 1.0f ) },
+		qvtx{ vec2( 1.0f,1.0f ),   vec2( 1.0f, 1.0f ) },
+		qvtx{ vec2( -1.0f,1.0f ),  vec2( 0.0f, 1.0f ) },
+		qvtx{ vec2( -1.0f,-1.0f ), vec2( 0.0f, 0.0f ) },
+	};
+	m_dc.va       = m_context->create_vertex_array( quad, 6, nv::STATIC_DRAW );
+	m_dc.va_count = 6;
+	m_dc.image    = t;
+
+	m_dc.p = m_context->create_program( nv_gfx_terminal_vs, nv_gfx_terminal_fs );
+
+	m_data->buffer = m_context->create_buffer( nv::UNIFORM_BUFFER, nv::DYNAMIC_DRAW, tsize.x * tsize.y * sizeof( gfx_terminal_uniform_block ), m_data->data );
+	m_context->bind( m_data->buffer, 7 );
+	m_context->get_device()->set_opt_uniform( m_dc.p, "term_size", vec2( tsize ) );
+//	m_context->get_device()->set_opt_uniform( m_dc.p, "dev_size", vec2( psize ) );
+	m_context->get_device()->set_opt_uniform( m_dc.p, "gylph_size", vec2( 8,8 ) );
+	m_context->get_device()->set_opt_uniform( m_dc.p, "nv_t_diffuse", int( nv::TEX_DIFFUSE ) );
+	m_context->get_device()->bind_block( m_dc.p, "terminal_block", 7 );
+	m_update_needed = false;
+}
+
+void gfx_terminal::update()
+{
+	m_context->bind( m_data->buffer, 7 );
+	m_context->update( m_data->buffer, m_data->data, 0, m_data->size.x * m_data->size.y * sizeof( gfx_terminal_uniform_block ) );
+	m_update_needed = false;
+}
+
+void gfx_terminal::print( position p, term_color fgcolor, term_color bgcolor, char ch )
+{
+	m_update_needed = true;
+	( *m_data )[position( p.x - 1, p.y - 1)].set( fgcolor, bgcolor, ch );
+}
+
+void gfx_terminal::clear( rectangle r, term_color fgcolor, term_color bgcolor )
+{
+	m_update_needed = true;
+	for ( int x = r.ul.x - 1; x <= r.lr.x - 1; ++x )
+		for ( int y = r.ul.y - 1; y <= r.lr.y - 1; ++y )
+			(*m_data)[ position( x, y ) ].set( fgcolor, bgcolor, ' ' );
+}
+
+void gfx_terminal::clear()
+{
+	m_update_needed = true;
+	for ( int i = 0; i < m_data->size.x * m_data->size.y; ++i )
+		m_data->data[i].set( term_color::LIGHTGRAY, term_color::TRANSPARENT, ' ' );
+}
+
+bool gfx_terminal::poll( io_event & kevent )
+{
+	return false;
+}
+
+void gfx_terminal::set_cursor( position p )
+{
+}
+
+void gfx_terminal::show_cursor()
+{
+}
+
+void gfx_terminal::hide_cursor()
+{
+}
+
+gfx_terminal::~gfx_terminal()
+{
+	delete m_data;
+}
+
