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

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