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

Last change on this file since 281 was 281, checked in by epyon, 11 years ago
  • animation key raw sizes (the whole system will be dumped though)
  • bugfix for string_table
  • nv::slot is now an enum class
File size: 8.6 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, const std::string& shader_path  )
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( shader_path + ".vert" ), nv::slurp( shader_path + ".frag" ) );
114        m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
115
116        vertex_buffer* vb = (vertex_buffer*)sr->buffer.get_buffer();
117        sr->varray->add_vertex_buffer( slot::POSITION, vb, nv::INT,   2, 0, sizeof( vertex ), false );
118        sr->varray->add_vertex_buffer( slot::TEXCOORD, vb, nv::FLOAT, 2, offset_of( &vertex::tcoord ), sizeof( vertex ), false );
119        sr->varray->add_vertex_buffer( slot::COLOR,    vb, nv::FLOAT, 4, offset_of( &vertex::color ), sizeof( vertex ), false );
120
121        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
122        sr->texture = m_window->get_device()->create_texture2d( m_atlas.get_size(), nv::RGBA, nv::UBYTE, sampler, nullptr );
123
124        m_render_state.depth_test.enabled = false;
125        m_render_state.culling.enabled    = false;
126        m_render_state.blending.enabled   = true;
127        m_render_state.blending.src_rgb_factor   = blending::SRC_ALPHA;
128        m_render_state.blending.dst_rgb_factor   = blending::ONE_MINUS_SRC_ALPHA;
129        m_render_state.blending.src_alpha_factor = blending::SRC_ALPHA;
130        m_render_state.blending.dst_alpha_factor = blending::ONE_MINUS_SRC_ALPHA;
131}
132
133texture_font* renderer::get_font( size_t name ) const
134{
135        if ( name >= m_fonts.size() ) return nullptr;
136        return m_fonts[ name ];
137}
138
139nv::vec4 renderer::get_image( size_t name ) const
140{
141        if ( name >= m_images.size() ) return nv::vec4();
142        return m_images[ name ];
143}
144
145size_t renderer::load_font( const std::string& filename, size_t size )
146{
147        std::string id_name( filename );
148        id_name.append( to_string( size ) );
149        auto i = m_font_names.find( id_name );
150        if ( i != m_font_names.end() )
151        {
152                return i->second;
153        }
154        size_t result = (size_t)m_fonts.size();
155        texture_font* f = new texture_font( &m_atlas, filename.c_str(), (float)size );
156        f->load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " );
157        m_fonts.push_back( f );
158        m_reupload = true;
159        m_font_names[ id_name ] = result;
160        return result;
161}
162
163size_t renderer::load_image( const std::string& filename )
164{
165        auto i = m_image_names.find( filename );
166        if ( i != m_image_names.end() )
167        {
168                return i->second;
169        }
170        size_t result = m_images.size();
171        image_data* data = m_window->get_device()->create_image_data( filename );
172        // TODO: Repitching
173        assert( data->get_depth() == 4 );
174        region r = m_atlas.get_region( data->get_size() );
175        m_atlas.set_region( r, data->get_data() );
176        delete data;
177        m_reupload = true;
178        m_image_names[ filename ] = result;
179        return result;
180}
181
182void renderer::load_style( const std::string& filename )
183{
184        m_style.load_style( filename );
185}
186
187void renderer::redraw( element* e, uint32 )
188{
189        screen_render_data* sr = (screen_render_data*)m_render_data;
190        if ( e->m_render_data == nullptr )
191        {
192                e->m_render_data = new element_render_data( &sr->buffer );
193        }
194        element_render_data* er = (element_render_data*)(e->m_render_data);
195        size_t size_before = er->buffer.data().size();
196
197        std::vector< gui_quad >& qvec = er->buffer.lock();
198
199        qvec.clear();
200        rectangle abs = e->m_absolute;
201        if ( e->m_absolute != m_area )
202        {
203                int border;
204                vec4 color;
205                std::string path;
206                std::string text;
207                if ( m_style.get( e, "border", border ) && m_style.get( e, "border_color", color ) )
208                {
209                        rectangle inner = abs.shrinked( border );
210                        qvec.emplace_back( abs.ul, inner.ul, inner.ur(), abs.ur(), color );
211                        qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
212                        qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
213                        qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
214                        abs = inner;
215                }
216
217                if ( m_style.get( e, "background_color", color ) )
218                {
219                        qvec.emplace_back( abs.ul, abs.lr, color );
220                }
221
222                text = e->m_text;
223                if ( !text.empty() )
224                {
225                        if ( m_style.get( e, "text_color", color ) && m_style.get( e, "text_font", path ) && m_style.get( e, "text_size", border ) )
226                        {
227                                size_t font_id = load_font( path, (uint16)border );
228                                texture_font* font = get_font( font_id );
229                                position p = abs.ul + position( 0, border );
230                                for ( char c : text )
231                                {
232                                        const texture_glyph* g = font->get_glyph( static_cast<uint16>(c) );
233                                        if (g)
234                                        {
235                                                position gp = position( g->offset.x, -g->offset.y );
236                                                position p2 = p + g->size + gp;
237                                                qvec.emplace_back( p + gp, p2, color, g->tl, g->br );
238                                                p += g->advance;
239                                        }
240                                }
241                        }
242                }
243        }
244
245        if ( size_before != er->buffer.data().size() )
246        {
247                sr->buffer.reset();
248        }
249}
250
251void renderer::draw( element* e )
252{
253        element_render_data* er = (element_render_data*)(e->m_render_data);
254        er->buffer.commit();
255}
256
257void renderer::draw()
258{
259        screen_render_data* sr = (screen_render_data*)m_render_data;
260
261        if ( m_reupload )
262        {
263                sr->texture->assign( (void*)m_atlas.get_data() );
264                m_reupload = false;
265        }
266
267        if ( sr->buffer.commit() )
268        {
269                nv::vertex_buffer* vb = (nv::vertex_buffer*)sr->buffer.get_buffer();
270                sr->varray->update_vertex_buffer( nv::slot::POSITION, vb, false );
271                sr->varray->update_vertex_buffer( nv::slot::TEXCOORD, vb, false );
272                sr->varray->update_vertex_buffer( nv::slot::COLOR,    vb, false );
273        }
274        sr->texture->bind( nv::TEX_DIFFUSE );
275        m_window->get_context()->draw( TRIANGLES, m_render_state, m_scene_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
276}
277
278renderer::~renderer()
279{
280        for ( auto p : m_fonts )
281        {
282                delete p;
283        }
284        delete m_render_data;
285}
Note: See TracBrowser for help on using the repository browser.