source: trunk/src/gui/gui_gfx_renderer.cc @ 454

Last change on this file since 454 was 444, checked in by epyon, 10 years ago
  • slowly fixing up gui
File size: 12.2 KB
Line 
1// Copyright (C) 2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/gui/gui_gfx_renderer.hh"
8
9#include "nv/interface/device.hh"
10#include "nv/interface/context.hh"
11#include "nv/core/logging.hh"
12
13static const char *nv_gui_vertex_shader = R"(
14#version 120
15attribute vec2 nv_position;
16attribute vec2 nv_texcoord;
17attribute vec4 nv_color;
18varying vec4 v_color;
19varying vec2 v_texcoord;
20uniform mat4 nv_m_projection;
21void main(void)
22{
23        gl_Position = nv_m_projection * vec4(nv_position.x, nv_position.y, 0.0, 1.0);
24        v_texcoord  = nv_texcoord;
25        v_color     = nv_color;
26}
27)";
28
29static const char *nv_gui_fragment_shader = R"(
30#version 120
31varying vec4 v_color;
32varying vec2 v_texcoord;
33uniform sampler2D nv_t_diffuse;
34void main(void)
35{
36        vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );
37        gl_FragColor   = v_color * tex_color;
38}
39)";
40
41
42using namespace nv;
43using namespace nv::gui;
44
45struct vertex
46{
47        ivec2 position;
48        vec2  texcoord;
49        vec4  color;
50        vertex() {}
51        vertex( const nv::ivec2& cr, const nv::vec2& tc, const nv::vec4& c )
52                : position( cr ), texcoord( tc ), color( c )
53        {
54        }
55};
56
57const ivec2 atlas_size = ivec2( 1024, 1024 );
58
59struct gui_quad
60{
61        vertex vtx[6];
62        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color )
63        {
64                set_color( color );
65                vtx[0].position = coorda;
66                vtx[1].position = nv::ivec2( coorda.x, coordb.y );
67                vtx[2].position = coordb;
68                vtx[3].position = coordb;
69                vtx[4].position = nv::ivec2( coordb.x, coorda.y );
70                vtx[5].position = coorda;
71        }
72        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color, const nv::vec2& tcoorda, const nv::vec2& tcoordb )
73        {
74                set_color( color );
75                vtx[0].position = coorda;
76                vtx[1].position = nv::ivec2( coorda.x, coordb.y );
77                vtx[2].position = coordb;
78                vtx[3].position = coordb;
79                vtx[4].position = nv::ivec2( coordb.x, coorda.y );
80                vtx[5].position = coorda;
81                vtx[0].texcoord = tcoorda;
82                vtx[1].texcoord = nv::vec2( tcoorda.x, tcoordb.y );
83                vtx[2].texcoord = tcoordb;
84                vtx[3].texcoord = tcoordb;
85                vtx[4].texcoord = nv::vec2( tcoordb.x, tcoorda.y );
86                vtx[5].texcoord = tcoorda;
87        }
88        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::ivec2& coordc, const nv::ivec2& coordd, const nv::vec4& color )
89        {
90                set_color( color );
91                vtx[0].position = coorda;
92                vtx[1].position = coordb;
93                vtx[2].position = coordc;
94                vtx[3].position = coordc;
95                vtx[4].position = coordd;
96                vtx[5].position = coorda;
97        }
98        inline void set_color( const nv::vec4& color )
99        {
100                vtx[0].color = color; vtx[1].color = color;     vtx[2].color = color;
101                vtx[3].color = color; vtx[4].color = color;     vtx[5].color = color;
102        }
103};
104
105
106class screen_render_data : public render_data
107{
108public:
109        screen_render_data( context* actx, nv::size_t initial_size )
110                : buffer( actx, VERTEX_BUFFER, DYNAMIC_DRAW, initial_size ), ctx( actx ), varray(), shader()
111        {
112
113        }
114        ~screen_render_data()
115        {
116                ctx->get_device()->release( shader );
117                ctx->release( varray );
118        }
119
120        nv::sliced_buffer<gui_quad> buffer;
121        nv::context*      ctx;
122        nv::texture       tex;
123        nv::vertex_array  varray;
124        nv::program       shader;
125};
126
127class element_render_data : public render_data
128{
129public:
130        element_render_data( nv::sliced_buffer<gui_quad>* cbuffer )
131                : buffer( cbuffer )
132        {
133        }
134
135        nv::buffer_slice< gui_quad > buffer;
136};
137
138gfx_renderer::gfx_renderer( window* w )
139        : m_window( w )
140        , m_atlas( atlas_size, 4 )
141        , m_reupload( true )
142{
143        NV_LOG_TRACE( "Creating GUI renderer..." );
144        m_context = w->get_context();
145        m_area.dim( dimension( w->get_width(), w->get_height() ) );
146        region white = m_atlas.get_region( ivec2( 3, 3 ) );
147        size_t wsize = m_atlas.get_depth() * 4 * 4;
148        uint8* wfill = new uint8[m_atlas.get_depth() * 4 * 4];
149        raw_fill( wfill, wfill + wsize, 255 );
150        white.pos = ivec2();
151        m_atlas.set_region( white, wfill );
152        delete[] wfill;
153
154        NV_LOG_TRACE( "Creating render data..." );
155        screen_render_data* sr = new screen_render_data( w->get_context(), 1024 );
156        m_render_data = sr;
157        sr->shader = m_window->get_device()->create_program( nv_gui_vertex_shader, nv_gui_fragment_shader );
158        m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
159
160        sr->varray = m_window->get_context()->create_vertex_array();
161        buffer vb = sr->buffer.get_buffer();
162        m_window->get_context()->add_vertex_buffers< vertex >( sr->varray, vb );
163
164        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
165        sr->tex = m_window->get_device()->create_texture( m_atlas.get_size(), image_format( nv::RGBA, nv::UBYTE ), sampler, nullptr );
166
167        m_render_state.depth_test.enabled = false;
168        m_render_state.culling.enabled = false;
169        m_render_state.blending.enabled = true;
170        m_render_state.blending.src_rgb_factor = blending::SRC_ALPHA;
171        m_render_state.blending.dst_rgb_factor = blending::ONE_MINUS_SRC_ALPHA;
172        m_render_state.blending.src_alpha_factor = blending::SRC_ALPHA;
173        m_render_state.blending.dst_alpha_factor = blending::ONE_MINUS_SRC_ALPHA;
174        NV_LOG_TRACE( "GUI Renderer created" );
175}
176
177texture_font* gfx_renderer::get_font( nv::size_t name ) const
178{
179        if ( name >= m_fonts.size() ) return nullptr;
180        return m_fonts[name];
181}
182
183const image_info* gfx_renderer::get_image( nv::size_t name ) const
184{
185        if ( name >= m_images.size() ) return nullptr;
186        return &m_images[name];
187}
188
189nv::size_t gfx_renderer::load_font( const string_view& filename, nv::size_t size )
190{
191        string128 id( filename );
192        id.append( size );
193        auto i = m_font_names.find( id );
194        if ( i != m_font_names.end() )
195        {
196                return i->second;
197        }
198        size_t result = m_fonts.size();
199        texture_font* f = new texture_font( &m_atlas, filename.data(), static_cast<float>( size ) );
200        f->load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " );
201        m_fonts.push_back( f );
202        m_reupload = true;
203        m_font_names[ id ] = result;
204        return result;
205}
206
207nv::size_t gfx_renderer::load_image( const string_view& filename )
208{
209        auto i = m_image_names.find( filename );
210        if ( i != m_image_names.end() )
211        {
212                return i->second;
213        }
214        size_t result = m_images.size();
215        image_data* data = m_window->get_device()->create_image_data( filename );
216        // TODO: Repitching
217        assert( data->get_depth() == 4 );
218        region r = m_atlas.get_region( data->get_size() );
219        m_atlas.set_region( r, data->get_data() );
220        m_images.emplace_back( vec2( r.pos ) / vec2( atlas_size ), vec2( r.size + r.pos ) / vec2( atlas_size ), r.size );
221        delete data;
222        m_reupload = true;
223        m_image_names[filename] = result;
224        return result;
225}
226
227void gfx_renderer::redraw( element* e, uint32 )
228{
229        screen_render_data* sr = reinterpret_cast< screen_render_data* >( m_render_data );
230        if ( e->m_render_data == nullptr )
231        {
232                e->m_render_data = new element_render_data( &sr->buffer );
233        }
234        element_render_data* er = reinterpret_cast< element_render_data* >( e->m_render_data );
235        size_t size_before = er->buffer.data().size();
236
237        vector< gui_quad >& qvec = er->buffer.lock();
238
239        qvec.clear();
240        rectangle abs = e->m_absolute;
241        if ( e->m_absolute != m_area )
242        {
243                int border = 0;
244                vec4 color;
245                string128 path;
246                const char* stext[] = { "", "selected", "hover" };
247                const char* selector = stext[border];
248                if ( e->m_flags[HOVER] )    selector = stext[2];
249                if ( e->m_flags[SELECTED] ) selector = stext[1];
250                NV_LOG_INFO( "redraw" );
251
252                if ( m_style.get( e, "skin", selector, path ) )
253                {
254                        size_t image_id = load_image( path );
255                        const image_info* image = get_image( image_id );
256                        if ( image )
257                        {
258                                color = vec4( 2, 2, 2, 1 );
259                                ivec2 isize3 = image->size / 3;
260                                ivec2 isize3x = ivec2( isize3.x, 0 );
261                                ivec2 isize3y = ivec2( 0, isize3.y );
262                                vec2 tsize = ( image->t2 - image->t1 );
263                                vec2 tsize3 = ( image->t2 - image->t1 ) / 3.0f;
264                                vec2 tsize32 = ( image->t2 - image->t1 ) * ( 2.0f / 3.0f );
265                                vec2 tsizex = vec2( tsize.x, 0.0f );
266                                //vec2 tsizey = vec2( 0.0f, tsize.y );
267                                vec2 tsize3x = vec2( tsize3.x, 0.0f );
268                                vec2 tsize3y = vec2( 0.0f, tsize3.y );
269                                vec2 tsize3x2 = vec2( tsize32.x, 0.0f );
270                                vec2 tsize3y2 = vec2( 0.0f, tsize32.y );
271
272                                rectangle inner = abs.shrinked( isize3 );
273                                qvec.emplace_back( abs.ul, inner.ul, color, image->t1, image->t1 + tsize3 );
274                                qvec.emplace_back( abs.ul + isize3x, inner.ur(), color, image->t1 + tsize3x, image->t1 + tsize3x2 + tsize3y );
275                                qvec.emplace_back( abs.ur() - isize3x, inner.ur() + isize3x, color, image->t1 + tsize3x2, image->t1 + tsizex + tsize3y );
276
277                                qvec.emplace_back( abs.ul + isize3y, inner.ll(), color, image->t1 + tsize3y, image->t1 + tsize3y2 + tsize3x );
278                                qvec.emplace_back( inner.ul, inner.lr, color, image->t1 + tsize3, image->t1 + tsize32 );
279                                qvec.emplace_back( inner.ur(), inner.lr + isize3x, color, image->t1 + tsize3 + tsize3x, image->t1 + tsize32 + tsize3x );
280
281
282                                qvec.emplace_back( abs.ll() - isize3y, inner.ll() + isize3y, color, image->t1 + tsize3y2, image->t1 + tsize3y2 + tsize3 );
283                                qvec.emplace_back( inner.ll(), abs.lr - isize3x, color, image->t1 + tsize3y2 + tsize3x, image->t1 + tsize32 + tsize3y );
284                                qvec.emplace_back( inner.lr, abs.lr, color, image->t1 + tsize32, image->t1 + tsize );
285
286
287                                //                              qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
288                                //                              qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
289                                //                              qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
290                                abs = inner;
291
292                        }
293
294                }
295                else
296                {
297
298                        if ( m_style.get( e, "border", selector, border ) && m_style.get( e, "border_color", selector, color ) )
299                        {
300                                rectangle inner = abs.shrinked( border );
301                                qvec.emplace_back( abs.ul, inner.ul, inner.ur(), abs.ur(), color );
302                                qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
303                                qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
304                                qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
305                                abs = inner;
306                        }
307
308                        if ( m_style.get( e, "background_color", selector, color ) )
309                        {
310                                qvec.emplace_back( abs.ul, abs.lr, color );
311                        }
312                }
313
314                e->m_text;
315                if ( !e->m_text.empty() )
316                {
317                        if ( m_style.get( e, "text_color", selector, color ) && m_style.get( e, "text_font", selector, path ) && m_style.get( e, "text_size", selector, border ) )
318                        {
319                                size_t font_id = load_font( path, size_t( border ) );
320                                texture_font* font = get_font( font_id );
321                                position p = abs.ul + position( 0, border );
322                                for ( char c : e->m_text )
323                                {
324                                        const texture_glyph* g = font->get_glyph( static_cast<uint16>( c ) );
325                                        if ( g )
326                                        {
327                                                position gp = position( g->offset.x, -g->offset.y );
328                                                position p2 = p + g->size + gp;
329                                                qvec.emplace_back( p + gp, p2, color, g->tl, g->br );
330                                                p += g->advance;
331                                        }
332                                }
333                        }
334                }
335        }
336
337        if ( size_before != er->buffer.data().size() )
338        {
339                sr->buffer.reset();
340        }
341}
342
343void gfx_renderer::on_hover_change( element* e )
344{
345        if ( e->m_flags[DIRTY_HOVER] )
346        {
347                NV_LOG_DEBUG( "on_hover_change" );
348                e->m_flags[DIRTY] = true;
349        }
350}
351
352void gfx_renderer::on_select_change( element* e )
353{
354        if ( e->m_flags[DIRTY_SELECT] )
355        {
356                NV_LOG_DEBUG( "on_select_change" );
357                e->m_flags[DIRTY] = true;
358        }
359}
360
361
362void gfx_renderer::draw( element* e )
363{
364        element_render_data* er = reinterpret_cast< element_render_data* >( e->m_render_data );
365        er->buffer.commit();
366}
367
368void gfx_renderer::draw()
369{
370        screen_render_data* sr = reinterpret_cast< screen_render_data* >( m_render_data );
371
372        if ( m_reupload )
373        {
374                m_context->update( sr->tex, m_atlas.get_data() );
375                m_reupload = false;
376        }
377
378        if ( sr->buffer.commit() )
379        {
380                buffer vb = sr->buffer.get_buffer();
381                m_context->replace_vertex_buffer( sr->varray, vb, false );
382        }
383        m_context->bind( sr->tex, TEX_DIFFUSE );
384        m_context->draw( TRIANGLES, m_render_state, m_scene_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
385}
386
387gfx_renderer::~gfx_renderer()
388{
389        for ( auto p : m_fonts )
390        {
391                delete p;
392        }
393        if ( m_render_data )
394        {
395                m_context->get_device()->release( reinterpret_cast< screen_render_data* >( m_render_data )->tex );
396                delete m_render_data;
397        }
398}
399
400void nv::gui::gfx_renderer::on_style_change( element* e )
401{
402        m_style.load_flags( e );
403}
Note: See TracBrowser for help on using the repository browser.