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

Last change on this file since 152 was 152, checked in by epyon, 12 years ago
  • cached_buffer has been renamed to sliced_buffer
File size: 8.9 KB
RevLine 
[126]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
[152]79        nv::sliced_buffer<gui_quad> buffer;
[126]80        nv::vertex_array* varray;
81        nv::program*      shader;
82        nv::texture2d*    texture;
83
84        int loc_coord;
85        int loc_color;
86        int loc_tcoord;
87};
88
89class element_render_data : public render_data
90{
91public:
[152]92        element_render_data( nv::sliced_buffer<gui_quad>* cbuffer )
[126]93                : buffer( cbuffer ) {}
94
95        nv::buffer_slice< gui_quad > buffer;
96};
97
98renderer::renderer( window* w )
99        : m_window(w)
100        , m_style()
101        , m_atlas( glm::ivec2( 1024, 1024 ), 4 )
102        , m_reupload( true )
103{
104        m_area.dim( dimension( w->get_width(), w->get_height() ) );
105        region white = m_atlas.get_region( ivec2(3,3) );
106        size_t wsize = m_atlas.get_depth()*4*4;
107        uint8* wfill = new uint8[m_atlas.get_depth()*4*4];
108        std::fill( wfill, wfill + wsize, 255 );
109        white.pos = ivec2();
110        m_atlas.set_region( white, wfill );
111        delete wfill;
112
113        screen_render_data* sr = new screen_render_data( w->get_device(), 1024 );
114        m_render_data = sr;
115        // ** EXTREMELY TEMPORARY!
116        sr->varray     = m_window->get_device()->create_vertex_array();
117        sr->shader     = m_window->get_device()->create_program( nv::slurp( "gui.vert" ), nv::slurp( "gui.frag" ) );
118        sr->loc_coord  = sr->shader->get_attribute("coord")->get_location();
119        sr->loc_tcoord = sr->shader->get_attribute("tcoord")->get_location();
120        sr->loc_color  = sr->shader->get_attribute("color")->get_location();
121        sr->shader->set_uniform( "tex", 0 );
122        glm::mat4 projection = glm::ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f, -1.0f, 1.0f );
123        sr->shader->set_uniform( "projection", projection );
124
125        vertex_buffer* vb = (vertex_buffer*)sr->buffer.get_buffer();
126        sr->varray->add_vertex_buffer( sr->loc_coord,  vb, nv::INT,   2, 0, sizeof( vertex ), false );
127        sr->varray->add_vertex_buffer( sr->loc_tcoord, vb, nv::FLOAT, 2, offset_of( &vertex::tcoord ), sizeof( vertex ), false );
128        sr->varray->add_vertex_buffer( sr->loc_color,  vb, nv::FLOAT, 4, offset_of( &vertex::color ), sizeof( vertex ), false );
129
130        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
131        sr->texture = m_window->get_device()->create_texture2d( m_atlas.get_size(), nv::RGBA, nv::UBYTE, sampler, nullptr );
132
133        m_render_state.depth_test.enabled = false;
134        m_render_state.culling.enabled    = false;
135        m_render_state.blending.enabled   = true;
136        m_render_state.blending.src_rgb_factor   = blending::SRC_ALPHA;
137        m_render_state.blending.dst_rgb_factor   = blending::ONE_MINUS_SRC_ALPHA;
138        m_render_state.blending.src_alpha_factor = blending::SRC_ALPHA;
139        m_render_state.blending.dst_alpha_factor = blending::ONE_MINUS_SRC_ALPHA;
140}
141
142texture_font* renderer::get_font( size_t name ) const
143{
144        if ( name >= m_fonts.size() ) return nullptr;
145        return m_fonts[ name ];
146}
147
148nv::vec4 renderer::get_image( size_t name ) const
149{
150        if ( name >= m_images.size() ) return nv::vec4();
151        return m_images[ name ];
152}
153
154size_t renderer::load_font( const std::string& filename, size_t size )
155{
156        std::string id_name( filename );
157        id_name.append( to_string( size ) );
158        auto i = m_font_names.find( id_name );
159        if ( i != m_font_names.end() )
160        {
161                return i->second;
162        }
163        size_t result = (size_t)m_fonts.size();
164        texture_font* f = new texture_font( &m_atlas, filename.c_str(), (float)size );
165        f->load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " );
166        m_fonts.push_back( f );
167        m_reupload = true;
168        m_font_names[ id_name ] = result;
169        return result;
170}
171
172size_t renderer::load_image( const std::string& filename )
173{
174        auto i = m_image_names.find( filename );
175        if ( i != m_image_names.end() )
176        {
177                return i->second;
178        }
179        size_t result = m_images.size();
180        image_data* data = m_window->get_device()->create_image_data( filename );
181        // TODO: Repitching
182        assert( data->get_depth() == 4 );
183        region r = m_atlas.get_region( data->get_size() );
184        m_atlas.set_region( r, data->get_data() );
185        delete data;
186        m_reupload = true;
187        m_image_names[ filename ] = result;
188        return result;
189}
190
191void renderer::load_style( const std::string& filename )
192{
193        m_style.load_style( filename );
194}
195
196void renderer::redraw( element* e, uint32 )
197{
198        screen_render_data* sr = (screen_render_data*)m_render_data;
199        if ( e->m_render_data == nullptr )
200        {
201                e->m_render_data = new element_render_data( &sr->buffer );
202        }
203        element_render_data* er = (element_render_data*)(e->m_render_data);
204        size_t size_before = er->buffer.data().size();
205
206        std::vector< gui_quad >& qvec = er->buffer.lock();
207
208        qvec.clear();
209        rectangle abs = e->get_absolute();
210        if ( e->get_absolute() != m_area )
211        {
212                int border;
213                vec4 color;
214                std::string path;
215                std::string text;
216                if ( m_style.get( e, "border", border ) && m_style.get( e, "border_color", color ) )
217                {
218                        rectangle inner = abs.shrinked( border );
219                        qvec.emplace_back( abs.ul, inner.ul, inner.ur(), abs.ur(), color );
220                        qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
221                        qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
222                        qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
223                        abs = inner;
224                }
225
226                if ( m_style.get( e, "background_color", color ) )
227                {
228                        qvec.emplace_back( abs.ul, abs.lr, color );
229                }
230
231                text = e->get_text();
232                if ( !text.empty() )
233                {
234                        if ( m_style.get( e, "text_color", color ) && m_style.get( e, "text_font", path ) && m_style.get( e, "text_size", border ) )
235                        {
236                                size_t font_id = load_font( path, (uint16)border );
237                                texture_font* font = get_font( font_id );
238                                position p = abs.ul + position( 0, border );
239                                for ( char c : text )
240                                {
241                                        const texture_glyph* g = font->get_glyph( static_cast<uint16>(c) );
242                                        if (g)
243                                        {
244                                                position gp = position( g->offset.x, -g->offset.y );
245                                                position p2 = p + g->size + gp;
246                                                qvec.emplace_back( p + gp, p2, color, g->tl, g->br );
247                                                p += g->advance;
248                                        }
249                                }
250                        }
251                }
252        }
253
254        if ( size_before != er->buffer.data().size() )
255        {
256                sr->buffer.reset();
257        }
258}
259
260void renderer::draw( element* e )
261{
262        element_render_data* er = (element_render_data*)(e->m_render_data);
263        er->buffer.commit();
264}
265
266void renderer::draw()
267{
268        screen_render_data* sr = (screen_render_data*)m_render_data;
269
270        if ( m_reupload )
271        {
272                sr->texture->assign( (void*)m_atlas.get_data() );
273                m_reupload = false;
274        }
275
276        if ( sr->buffer.commit() )
277        {
278                nv::vertex_buffer* vb = (nv::vertex_buffer*)sr->buffer.get_buffer();
279                sr->varray->update_vertex_buffer( sr->loc_coord,  vb, false );
280                sr->varray->update_vertex_buffer( sr->loc_tcoord, vb, false );
281                sr->varray->update_vertex_buffer( sr->loc_color,  vb, false );
282        }
283        sr->texture->bind( 0 );
284        sr->shader->set_uniform( "tex", 0 );
285        m_window->get_context()->draw( TRIANGLES, m_render_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
286}
287
288renderer::~renderer()
289{
290        for ( auto p : m_fonts )
291        {
292                delete p;
293        }
294        delete m_render_data;
295}
Note: See TracBrowser for help on using the repository browser.