source: trunk/src/gui/gui_renderer.cc @ 161

Last change on this file since 161 was 161, checked in by epyon, 12 years ago
  • unified naming of attributes in nv
  • predefined attribute bindings based on unified names
  • unified naming of attributes in all tests
File size: 8.7 KB
Line 
1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/gui/gui_renderer.hh"
8
9#include <glm/gtc/matrix_transform.hpp>
10
11#include "nv/interface/device.hh"
12#include "nv/interface/context.hh"
13
14using namespace nv;
15using namespace nv::gui;
16
17struct gui_quad
18{
19        vertex vtx[6];
20        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color )
21        {
22                set_color( color );
23                vtx[0].coord = coorda;
24                vtx[1].coord = nv::ivec2( coorda.x, coordb.y );
25                vtx[2].coord = coordb;
26                vtx[3].coord = coordb;
27                vtx[4].coord = nv::ivec2( coordb.x, coorda.y );
28                vtx[5].coord = coorda;
29        }
30        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color, const nv::vec2& tcoorda, const nv::vec2& tcoordb )
31        {
32                set_color( color );
33                vtx[0].coord = coorda;
34                vtx[1].coord = nv::ivec2( coorda.x, coordb.y );
35                vtx[2].coord = coordb;
36                vtx[3].coord = coordb;
37                vtx[4].coord = nv::ivec2( coordb.x, coorda.y );
38                vtx[5].coord = coorda;
39                vtx[0].tcoord = tcoorda;
40                vtx[1].tcoord = nv::vec2( tcoorda.x, tcoordb.y );
41                vtx[2].tcoord = tcoordb;
42                vtx[3].tcoord = tcoordb;
43                vtx[4].tcoord = nv::vec2( tcoordb.x, tcoorda.y );
44                vtx[5].tcoord = tcoorda;
45        }
46        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::ivec2& coordc, const nv::ivec2& coordd, const nv::vec4& color )
47        {
48                set_color( color );
49                vtx[0].coord = coorda;
50                vtx[1].coord = coordb;
51                vtx[2].coord = coordc;
52                vtx[3].coord = coordc;
53                vtx[4].coord = coordd;
54                vtx[5].coord = coorda;
55        }
56        inline void set_color( const nv::vec4& color )
57        {
58                vtx[0].color = color; vtx[1].color = color;     vtx[2].color = color;
59                vtx[3].color = color; vtx[4].color = color;     vtx[5].color = color;
60        }
61};
62
63
64class screen_render_data : public render_data
65{
66public:
67        screen_render_data( device* dev, size_t initial_size )
68                : buffer( dev, nv::DYNAMIC_DRAW, initial_size ), varray( nullptr ), shader(nullptr), texture(nullptr)
69        {
70
71        }
72        ~screen_render_data()
73        {
74                delete shader;
75                delete varray;
76                delete texture;
77        }
78
79        nv::sliced_buffer<gui_quad> buffer;
80        nv::vertex_array* varray;
81        nv::program*      shader;
82        nv::texture2d*    texture;
83};
84
85class element_render_data : public render_data
86{
87public:
88        element_render_data( nv::sliced_buffer<gui_quad>* cbuffer )
89                : buffer( cbuffer ) {}
90
91        nv::buffer_slice< gui_quad > buffer;
92};
93
94renderer::renderer( window* w )
95        : m_window(w)
96        , m_style()
97        , m_atlas( glm::ivec2( 1024, 1024 ), 4 )
98        , m_reupload( true )
99{
100        m_area.dim( dimension( w->get_width(), w->get_height() ) );
101        region white = m_atlas.get_region( ivec2(3,3) );
102        size_t wsize = m_atlas.get_depth()*4*4;
103        uint8* wfill = new uint8[m_atlas.get_depth()*4*4];
104        std::fill( wfill, wfill + wsize, 255 );
105        white.pos = ivec2();
106        m_atlas.set_region( white, wfill );
107        delete wfill;
108
109        screen_render_data* sr = new screen_render_data( w->get_device(), 1024 );
110        m_render_data = sr;
111        // ** EXTREMELY TEMPORARY!
112        sr->varray     = m_window->get_device()->create_vertex_array();
113        sr->shader     = m_window->get_device()->create_program( nv::slurp( "gui.vert" ), nv::slurp( "gui.frag" ) );
114        sr->shader->set_uniform( "tex", 0 );
115        glm::mat4 projection = glm::ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f, -1.0f, 1.0f );
116        sr->shader->set_uniform( "nv_projection", projection );
117
118        vertex_buffer* vb = (vertex_buffer*)sr->buffer.get_buffer();
119        sr->varray->add_vertex_buffer( slot::POSITION, vb, nv::INT,   2, 0, sizeof( vertex ), false );
120        sr->varray->add_vertex_buffer( slot::TEXCOORD, vb, nv::FLOAT, 2, offset_of( &vertex::tcoord ), sizeof( vertex ), false );
121        sr->varray->add_vertex_buffer( slot::COLOR,    vb, nv::FLOAT, 4, offset_of( &vertex::color ), sizeof( vertex ), false );
122
123        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
124        sr->texture = m_window->get_device()->create_texture2d( m_atlas.get_size(), nv::RGBA, nv::UBYTE, sampler, nullptr );
125
126        m_render_state.depth_test.enabled = false;
127        m_render_state.culling.enabled    = false;
128        m_render_state.blending.enabled   = true;
129        m_render_state.blending.src_rgb_factor   = blending::SRC_ALPHA;
130        m_render_state.blending.dst_rgb_factor   = blending::ONE_MINUS_SRC_ALPHA;
131        m_render_state.blending.src_alpha_factor = blending::SRC_ALPHA;
132        m_render_state.blending.dst_alpha_factor = blending::ONE_MINUS_SRC_ALPHA;
133}
134
135texture_font* renderer::get_font( size_t name ) const
136{
137        if ( name >= m_fonts.size() ) return nullptr;
138        return m_fonts[ name ];
139}
140
141nv::vec4 renderer::get_image( size_t name ) const
142{
143        if ( name >= m_images.size() ) return nv::vec4();
144        return m_images[ name ];
145}
146
147size_t renderer::load_font( const std::string& filename, size_t size )
148{
149        std::string id_name( filename );
150        id_name.append( to_string( size ) );
151        auto i = m_font_names.find( id_name );
152        if ( i != m_font_names.end() )
153        {
154                return i->second;
155        }
156        size_t result = (size_t)m_fonts.size();
157        texture_font* f = new texture_font( &m_atlas, filename.c_str(), (float)size );
158        f->load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " );
159        m_fonts.push_back( f );
160        m_reupload = true;
161        m_font_names[ id_name ] = result;
162        return result;
163}
164
165size_t renderer::load_image( const std::string& filename )
166{
167        auto i = m_image_names.find( filename );
168        if ( i != m_image_names.end() )
169        {
170                return i->second;
171        }
172        size_t result = m_images.size();
173        image_data* data = m_window->get_device()->create_image_data( filename );
174        // TODO: Repitching
175        assert( data->get_depth() == 4 );
176        region r = m_atlas.get_region( data->get_size() );
177        m_atlas.set_region( r, data->get_data() );
178        delete data;
179        m_reupload = true;
180        m_image_names[ filename ] = result;
181        return result;
182}
183
184void renderer::load_style( const std::string& filename )
185{
186        m_style.load_style( filename );
187}
188
189void renderer::redraw( element* e, uint32 )
190{
191        screen_render_data* sr = (screen_render_data*)m_render_data;
192        if ( e->m_render_data == nullptr )
193        {
194                e->m_render_data = new element_render_data( &sr->buffer );
195        }
196        element_render_data* er = (element_render_data*)(e->m_render_data);
197        size_t size_before = er->buffer.data().size();
198
199        std::vector< gui_quad >& qvec = er->buffer.lock();
200
201        qvec.clear();
202        rectangle abs = e->get_absolute();
203        if ( e->get_absolute() != m_area )
204        {
205                int border;
206                vec4 color;
207                std::string path;
208                std::string text;
209                if ( m_style.get( e, "border", border ) && m_style.get( e, "border_color", color ) )
210                {
211                        rectangle inner = abs.shrinked( border );
212                        qvec.emplace_back( abs.ul, inner.ul, inner.ur(), abs.ur(), color );
213                        qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
214                        qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
215                        qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
216                        abs = inner;
217                }
218
219                if ( m_style.get( e, "background_color", color ) )
220                {
221                        qvec.emplace_back( abs.ul, abs.lr, color );
222                }
223
224                text = e->get_text();
225                if ( !text.empty() )
226                {
227                        if ( m_style.get( e, "text_color", color ) && m_style.get( e, "text_font", path ) && m_style.get( e, "text_size", border ) )
228                        {
229                                size_t font_id = load_font( path, (uint16)border );
230                                texture_font* font = get_font( font_id );
231                                position p = abs.ul + position( 0, border );
232                                for ( char c : text )
233                                {
234                                        const texture_glyph* g = font->get_glyph( static_cast<uint16>(c) );
235                                        if (g)
236                                        {
237                                                position gp = position( g->offset.x, -g->offset.y );
238                                                position p2 = p + g->size + gp;
239                                                qvec.emplace_back( p + gp, p2, color, g->tl, g->br );
240                                                p += g->advance;
241                                        }
242                                }
243                        }
244                }
245        }
246
247        if ( size_before != er->buffer.data().size() )
248        {
249                sr->buffer.reset();
250        }
251}
252
253void renderer::draw( element* e )
254{
255        element_render_data* er = (element_render_data*)(e->m_render_data);
256        er->buffer.commit();
257}
258
259void renderer::draw()
260{
261        screen_render_data* sr = (screen_render_data*)m_render_data;
262
263        if ( m_reupload )
264        {
265                sr->texture->assign( (void*)m_atlas.get_data() );
266                m_reupload = false;
267        }
268
269        if ( sr->buffer.commit() )
270        {
271                nv::vertex_buffer* vb = (nv::vertex_buffer*)sr->buffer.get_buffer();
272                sr->varray->update_vertex_buffer( nv::POSITION, vb, false );
273                sr->varray->update_vertex_buffer( nv::TEXCOORD, vb, false );
274                sr->varray->update_vertex_buffer( nv::COLOR,    vb, false );
275        }
276        sr->texture->bind( 0 );
277        sr->shader->set_uniform( "tex", 0 );
278        m_window->get_context()->draw( TRIANGLES, m_render_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
279}
280
281renderer::~renderer()
282{
283        for ( auto p : m_fonts )
284        {
285                delete p;
286        }
287        delete m_render_data;
288}
Note: See TracBrowser for help on using the repository browser.