// 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( uint8(ch) ); } }; 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::STREAM_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() { if ( m_update_needed ) { 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; }