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

Last change on this file since 322 was 322, checked in by epyon, 11 years ago
  • profiler control via define/NV_DEBUG
  • weird RELEASE mode audio error - need to investigate
  • fixed - render_state in RELEASE mode would not set depth_mask!
File size: 9.2 KB
RevLine 
[319]1// Copyright (C) 2012-2014 ChaosForge Ltd
[126]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"
[322]13#include "nv/core/logging.hh"
[126]14
[318]15static const char *nv_gui_vertex_shader =
16        "#version 120\n"
17        "attribute vec2 nv_position;\n"
18        "attribute vec2 nv_texcoord;\n"
19        "attribute vec4 nv_color;\n"
20        "varying vec4 v_color;\n"
21        "varying vec2 v_texcoord;\n"
22        "uniform mat4 nv_m_projection;\n"
23        "void main(void)\n"
24        "{\n"
25        "       gl_Position = nv_m_projection * vec4(nv_position.x, nv_position.y, 0.0, 1.0);\n"
26        "       v_texcoord  = nv_texcoord;\n"
27        "       v_color     = nv_color;\n"
28        "}\n";
29static const char *nv_gui_fragment_shader =
30        "#version 120\n"
31        "varying vec4 v_color;\n"
32        "varying vec2 v_texcoord;\n"
33        "uniform sampler2D nv_t_diffuse;\n"
34        "void main(void)\n"
35        "{\n"
36        "       vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );\n"
37        "       gl_FragColor   = v_color * tex_color;\n"
38        "}\n";
39
[126]40using namespace nv;
41using namespace nv::gui;
42
43struct gui_quad
44{
45        vertex vtx[6];
46        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color )
47        {
48                set_color( color );
[302]49                vtx[0].position = coorda;
50                vtx[1].position = nv::ivec2( coorda.x, coordb.y );
51                vtx[2].position = coordb;
52                vtx[3].position = coordb;
53                vtx[4].position = nv::ivec2( coordb.x, coorda.y );
54                vtx[5].position = coorda;
[126]55        }
56        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color, const nv::vec2& tcoorda, const nv::vec2& tcoordb )
57        {
58                set_color( color );
[302]59                vtx[0].position = coorda;
60                vtx[1].position = nv::ivec2( coorda.x, coordb.y );
61                vtx[2].position = coordb;
62                vtx[3].position = coordb;
63                vtx[4].position = nv::ivec2( coordb.x, coorda.y );
64                vtx[5].position = coorda;
65                vtx[0].texcoord = tcoorda;
66                vtx[1].texcoord = nv::vec2( tcoorda.x, tcoordb.y );
67                vtx[2].texcoord = tcoordb;
68                vtx[3].texcoord = tcoordb;
69                vtx[4].texcoord = nv::vec2( tcoordb.x, tcoorda.y );
70                vtx[5].texcoord = tcoorda;
[126]71        }
72        gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::ivec2& coordc, const nv::ivec2& coordd, const nv::vec4& color )
73        {
74                set_color( color );
[302]75                vtx[0].position = coorda;
76                vtx[1].position = coordb;
77                vtx[2].position = coordc;
78                vtx[3].position = coordc;
79                vtx[4].position = coordd;
80                vtx[5].position = coorda;
[126]81        }
82        inline void set_color( const nv::vec4& color )
83        {
84                vtx[0].color = color; vtx[1].color = color;     vtx[2].color = color;
85                vtx[3].color = color; vtx[4].color = color;     vtx[5].color = color;
86        }
87};
88
89
90class screen_render_data : public render_data
91{
92public:
[301]93        screen_render_data( context* actx, size_t initial_size )
[303]94                : buffer( actx, VERTEX_BUFFER, DYNAMIC_DRAW, initial_size ), ctx( actx ), varray(), shader()
[126]95        {
96
97        }
98        ~screen_render_data()
99        {
[303]100                ctx->get_device()->release( shader );
[313]101                ctx->release( varray );
[126]102        }
103
[152]104        nv::sliced_buffer<gui_quad> buffer;
[302]105        nv::context*      ctx;
[301]106        nv::texture       tex;
[302]107        nv::vertex_array  varray;
[303]108        nv::program       shader;
[126]109};
110
111class element_render_data : public render_data
112{
113public:
[152]114        element_render_data( nv::sliced_buffer<gui_quad>* cbuffer )
[126]115                : buffer( cbuffer ) {}
116
117        nv::buffer_slice< gui_quad > buffer;
118};
119
[318]120renderer::renderer( window* w )
[126]121        : m_window(w)
122        , m_style()
123        , m_atlas( glm::ivec2( 1024, 1024 ), 4 )
124        , m_reupload( true )
125{
[322]126        NV_LOG( LOG_TRACE, "Creating GUI renderer..." );
[299]127        m_context = w->get_context();
[126]128        m_area.dim( dimension( w->get_width(), w->get_height() ) );
129        region white = m_atlas.get_region( ivec2(3,3) );
130        size_t wsize = m_atlas.get_depth()*4*4;
131        uint8* wfill = new uint8[m_atlas.get_depth()*4*4];
132        std::fill( wfill, wfill + wsize, 255 );
133        white.pos = ivec2();
134        m_atlas.set_region( white, wfill );
[189]135        delete[] wfill;
[126]136
[322]137        NV_LOG( LOG_TRACE, "Creating render data..." );
[299]138        screen_render_data* sr = new screen_render_data( w->get_context(), 1024 );
[126]139        m_render_data = sr;
[318]140        sr->shader     = m_window->get_device()->create_program( nv_gui_vertex_shader, nv_gui_fragment_shader );
[267]141        m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
[126]142
[313]143        sr->varray     = m_window->get_context()->create_vertex_array();
[302]144        buffer vb      = sr->buffer.get_buffer();
[313]145        m_window->get_context()->add_vertex_buffers< vertex >( sr->varray, vb );
[126]146
147        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
[301]148        sr->tex = m_window->get_device()->create_texture( m_atlas.get_size(), image_format( nv::RGBA, nv::UBYTE ), sampler, nullptr );
[126]149
150        m_render_state.depth_test.enabled = false;
151        m_render_state.culling.enabled    = false;
152        m_render_state.blending.enabled   = true;
153        m_render_state.blending.src_rgb_factor   = blending::SRC_ALPHA;
154        m_render_state.blending.dst_rgb_factor   = blending::ONE_MINUS_SRC_ALPHA;
155        m_render_state.blending.src_alpha_factor = blending::SRC_ALPHA;
156        m_render_state.blending.dst_alpha_factor = blending::ONE_MINUS_SRC_ALPHA;
[322]157        NV_LOG( LOG_TRACE, "GUI Renderer created" );
[126]158}
159
160texture_font* renderer::get_font( size_t name ) const
161{
162        if ( name >= m_fonts.size() ) return nullptr;
163        return m_fonts[ name ];
164}
165
166nv::vec4 renderer::get_image( size_t name ) const
167{
168        if ( name >= m_images.size() ) return nv::vec4();
169        return m_images[ name ];
170}
171
172size_t renderer::load_font( const std::string& filename, size_t size )
173{
174        std::string id_name( filename );
175        id_name.append( to_string( size ) );
176        auto i = m_font_names.find( id_name );
177        if ( i != m_font_names.end() )
178        {
179                return i->second;
180        }
181        size_t result = (size_t)m_fonts.size();
182        texture_font* f = new texture_font( &m_atlas, filename.c_str(), (float)size );
183        f->load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " );
184        m_fonts.push_back( f );
185        m_reupload = true;
186        m_font_names[ id_name ] = result;
187        return result;
188}
189
190size_t renderer::load_image( const std::string& filename )
191{
192        auto i = m_image_names.find( filename );
193        if ( i != m_image_names.end() )
194        {
195                return i->second;
196        }
197        size_t result = m_images.size();
198        image_data* data = m_window->get_device()->create_image_data( filename );
199        // TODO: Repitching
200        assert( data->get_depth() == 4 );
201        region r = m_atlas.get_region( data->get_size() );
202        m_atlas.set_region( r, data->get_data() );
203        delete data;
204        m_reupload = true;
205        m_image_names[ filename ] = result;
206        return result;
207}
208
209void renderer::load_style( const std::string& filename )
210{
211        m_style.load_style( filename );
212}
213
214void renderer::redraw( element* e, uint32 )
215{
216        screen_render_data* sr = (screen_render_data*)m_render_data;
217        if ( e->m_render_data == nullptr )
218        {
219                e->m_render_data = new element_render_data( &sr->buffer );
220        }
221        element_render_data* er = (element_render_data*)(e->m_render_data);
222        size_t size_before = er->buffer.data().size();
223
224        std::vector< gui_quad >& qvec = er->buffer.lock();
225
226        qvec.clear();
[268]227        rectangle abs = e->m_absolute;
228        if ( e->m_absolute != m_area )
[126]229        {
230                int border;
231                vec4 color;
232                std::string path;
233                std::string text;
234                if ( m_style.get( e, "border", border ) && m_style.get( e, "border_color", color ) )
235                {
236                        rectangle inner = abs.shrinked( border );
237                        qvec.emplace_back( abs.ul, inner.ul, inner.ur(), abs.ur(), color );
238                        qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
239                        qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
240                        qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
241                        abs = inner;
242                }
243
244                if ( m_style.get( e, "background_color", color ) )
245                {
246                        qvec.emplace_back( abs.ul, abs.lr, color );
247                }
248
[268]249                text = e->m_text;
[126]250                if ( !text.empty() )
251                {
252                        if ( m_style.get( e, "text_color", color ) && m_style.get( e, "text_font", path ) && m_style.get( e, "text_size", border ) )
253                        {
254                                size_t font_id = load_font( path, (uint16)border );
255                                texture_font* font = get_font( font_id );
256                                position p = abs.ul + position( 0, border );
257                                for ( char c : text )
258                                {
259                                        const texture_glyph* g = font->get_glyph( static_cast<uint16>(c) );
260                                        if (g)
261                                        {
262                                                position gp = position( g->offset.x, -g->offset.y );
263                                                position p2 = p + g->size + gp;
264                                                qvec.emplace_back( p + gp, p2, color, g->tl, g->br );
265                                                p += g->advance;
266                                        }
267                                }
268                        }
269                }
270        }
271
272        if ( size_before != er->buffer.data().size() )
273        {
274                sr->buffer.reset();
275        }
276}
277
278void renderer::draw( element* e )
279{
280        element_render_data* er = (element_render_data*)(e->m_render_data);
281        er->buffer.commit();
282}
283
284void renderer::draw()
285{
286        screen_render_data* sr = (screen_render_data*)m_render_data;
287
288        if ( m_reupload )
289        {
[301]290                m_context->update( sr->tex, (void*)m_atlas.get_data() );
[126]291                m_reupload = false;
292        }
293
294        if ( sr->buffer.commit() )
295        {
[302]296                buffer vb = sr->buffer.get_buffer();
[313]297                m_context->replace_vertex_buffer( sr->varray, vb, false );
[126]298        }
[301]299        m_context->bind( sr->tex, TEX_DIFFUSE );
[299]300        m_context->draw( TRIANGLES, m_render_state, m_scene_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
[126]301}
302
303renderer::~renderer()
304{
305        for ( auto p : m_fonts )
306        {
307                delete p;
308        }
[301]309        if ( m_render_data )
310        {
[302]311                m_context->get_device()->release( ((screen_render_data*)m_render_data)->tex );
[301]312                delete m_render_data;
313        }
[126]314}
Note: See TracBrowser for help on using the repository browser.