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

Last change on this file since 313 was 313, checked in by epyon, 11 years ago
  • cleanup of context and device interfaces
  • create_vertex_array moved to context (as it's context bound)
  • added partial framebuffer functions to context
File size: 8.4 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 );
[302]23                vtx[0].position = coorda;
24                vtx[1].position = nv::ivec2( coorda.x, coordb.y );
25                vtx[2].position = coordb;
26                vtx[3].position = coordb;
27                vtx[4].position = nv::ivec2( coordb.x, coorda.y );
28                vtx[5].position = coorda;
[126]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 );
[302]33                vtx[0].position = coorda;
34                vtx[1].position = nv::ivec2( coorda.x, coordb.y );
35                vtx[2].position = coordb;
36                vtx[3].position = coordb;
37                vtx[4].position = nv::ivec2( coordb.x, coorda.y );
38                vtx[5].position = coorda;
39                vtx[0].texcoord = tcoorda;
40                vtx[1].texcoord = nv::vec2( tcoorda.x, tcoordb.y );
41                vtx[2].texcoord = tcoordb;
42                vtx[3].texcoord = tcoordb;
43                vtx[4].texcoord = nv::vec2( tcoordb.x, tcoorda.y );
44                vtx[5].texcoord = tcoorda;
[126]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 );
[302]49                vtx[0].position = coorda;
50                vtx[1].position = coordb;
51                vtx[2].position = coordc;
52                vtx[3].position = coordc;
53                vtx[4].position = coordd;
54                vtx[5].position = coorda;
[126]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:
[301]67        screen_render_data( context* actx, size_t initial_size )
[303]68                : buffer( actx, VERTEX_BUFFER, DYNAMIC_DRAW, initial_size ), ctx( actx ), varray(), shader()
[126]69        {
70
71        }
72        ~screen_render_data()
73        {
[303]74                ctx->get_device()->release( shader );
[313]75                ctx->release( varray );
[126]76        }
77
[152]78        nv::sliced_buffer<gui_quad> buffer;
[302]79        nv::context*      ctx;
[301]80        nv::texture       tex;
[302]81        nv::vertex_array  varray;
[303]82        nv::program       shader;
[126]83};
84
85class element_render_data : public render_data
86{
87public:
[152]88        element_render_data( nv::sliced_buffer<gui_quad>* cbuffer )
[126]89                : buffer( cbuffer ) {}
90
91        nv::buffer_slice< gui_quad > buffer;
92};
93
[234]94renderer::renderer( window* w, const std::string& shader_path  )
[126]95        : m_window(w)
96        , m_style()
97        , m_atlas( glm::ivec2( 1024, 1024 ), 4 )
98        , m_reupload( true )
99{
[299]100        m_context = w->get_context();
[126]101        m_area.dim( dimension( w->get_width(), w->get_height() ) );
102        region white = m_atlas.get_region( ivec2(3,3) );
103        size_t wsize = m_atlas.get_depth()*4*4;
104        uint8* wfill = new uint8[m_atlas.get_depth()*4*4];
105        std::fill( wfill, wfill + wsize, 255 );
106        white.pos = ivec2();
107        m_atlas.set_region( white, wfill );
[189]108        delete[] wfill;
[126]109
[299]110        screen_render_data* sr = new screen_render_data( w->get_context(), 1024 );
[126]111        m_render_data = sr;
112        // ** EXTREMELY TEMPORARY!
[234]113        sr->shader     = m_window->get_device()->create_program( nv::slurp( shader_path + ".vert" ), nv::slurp( shader_path + ".frag" ) );
[267]114        m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
[126]115
[313]116        sr->varray     = m_window->get_context()->create_vertex_array();
[302]117        buffer vb      = sr->buffer.get_buffer();
[313]118        m_window->get_context()->add_vertex_buffers< vertex >( sr->varray, vb );
[126]119
120        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
[301]121        sr->tex = m_window->get_device()->create_texture( m_atlas.get_size(), image_format( nv::RGBA, nv::UBYTE ), sampler, nullptr );
[126]122
123        m_render_state.depth_test.enabled = false;
124        m_render_state.culling.enabled    = false;
125        m_render_state.blending.enabled   = true;
126        m_render_state.blending.src_rgb_factor   = blending::SRC_ALPHA;
127        m_render_state.blending.dst_rgb_factor   = blending::ONE_MINUS_SRC_ALPHA;
128        m_render_state.blending.src_alpha_factor = blending::SRC_ALPHA;
129        m_render_state.blending.dst_alpha_factor = blending::ONE_MINUS_SRC_ALPHA;
130}
131
132texture_font* renderer::get_font( size_t name ) const
133{
134        if ( name >= m_fonts.size() ) return nullptr;
135        return m_fonts[ name ];
136}
137
138nv::vec4 renderer::get_image( size_t name ) const
139{
140        if ( name >= m_images.size() ) return nv::vec4();
141        return m_images[ name ];
142}
143
144size_t renderer::load_font( const std::string& filename, size_t size )
145{
146        std::string id_name( filename );
147        id_name.append( to_string( size ) );
148        auto i = m_font_names.find( id_name );
149        if ( i != m_font_names.end() )
150        {
151                return i->second;
152        }
153        size_t result = (size_t)m_fonts.size();
154        texture_font* f = new texture_font( &m_atlas, filename.c_str(), (float)size );
155        f->load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " );
156        m_fonts.push_back( f );
157        m_reupload = true;
158        m_font_names[ id_name ] = result;
159        return result;
160}
161
162size_t renderer::load_image( const std::string& filename )
163{
164        auto i = m_image_names.find( filename );
165        if ( i != m_image_names.end() )
166        {
167                return i->second;
168        }
169        size_t result = m_images.size();
170        image_data* data = m_window->get_device()->create_image_data( filename );
171        // TODO: Repitching
172        assert( data->get_depth() == 4 );
173        region r = m_atlas.get_region( data->get_size() );
174        m_atlas.set_region( r, data->get_data() );
175        delete data;
176        m_reupload = true;
177        m_image_names[ filename ] = result;
178        return result;
179}
180
181void renderer::load_style( const std::string& filename )
182{
183        m_style.load_style( filename );
184}
185
186void renderer::redraw( element* e, uint32 )
187{
188        screen_render_data* sr = (screen_render_data*)m_render_data;
189        if ( e->m_render_data == nullptr )
190        {
191                e->m_render_data = new element_render_data( &sr->buffer );
192        }
193        element_render_data* er = (element_render_data*)(e->m_render_data);
194        size_t size_before = er->buffer.data().size();
195
196        std::vector< gui_quad >& qvec = er->buffer.lock();
197
198        qvec.clear();
[268]199        rectangle abs = e->m_absolute;
200        if ( e->m_absolute != m_area )
[126]201        {
202                int border;
203                vec4 color;
204                std::string path;
205                std::string text;
206                if ( m_style.get( e, "border", border ) && m_style.get( e, "border_color", color ) )
207                {
208                        rectangle inner = abs.shrinked( border );
209                        qvec.emplace_back( abs.ul, inner.ul, inner.ur(), abs.ur(), color );
210                        qvec.emplace_back( abs.ul, abs.ll(), inner.ll(), inner.ul, color );
211                        qvec.emplace_back( inner.ur(), inner.lr, abs.lr, abs.ur(), color );
212                        qvec.emplace_back( inner.ll(), abs.ll(), abs.lr, inner.lr, color );
213                        abs = inner;
214                }
215
216                if ( m_style.get( e, "background_color", color ) )
217                {
218                        qvec.emplace_back( abs.ul, abs.lr, color );
219                }
220
[268]221                text = e->m_text;
[126]222                if ( !text.empty() )
223                {
224                        if ( m_style.get( e, "text_color", color ) && m_style.get( e, "text_font", path ) && m_style.get( e, "text_size", border ) )
225                        {
226                                size_t font_id = load_font( path, (uint16)border );
227                                texture_font* font = get_font( font_id );
228                                position p = abs.ul + position( 0, border );
229                                for ( char c : text )
230                                {
231                                        const texture_glyph* g = font->get_glyph( static_cast<uint16>(c) );
232                                        if (g)
233                                        {
234                                                position gp = position( g->offset.x, -g->offset.y );
235                                                position p2 = p + g->size + gp;
236                                                qvec.emplace_back( p + gp, p2, color, g->tl, g->br );
237                                                p += g->advance;
238                                        }
239                                }
240                        }
241                }
242        }
243
244        if ( size_before != er->buffer.data().size() )
245        {
246                sr->buffer.reset();
247        }
248}
249
250void renderer::draw( element* e )
251{
252        element_render_data* er = (element_render_data*)(e->m_render_data);
253        er->buffer.commit();
254}
255
256void renderer::draw()
257{
258        screen_render_data* sr = (screen_render_data*)m_render_data;
259
260        if ( m_reupload )
261        {
[301]262                m_context->update( sr->tex, (void*)m_atlas.get_data() );
[126]263                m_reupload = false;
264        }
265
266        if ( sr->buffer.commit() )
267        {
[302]268                buffer vb = sr->buffer.get_buffer();
[313]269                m_context->replace_vertex_buffer( sr->varray, vb, false );
[126]270        }
[301]271        m_context->bind( sr->tex, TEX_DIFFUSE );
[299]272        m_context->draw( TRIANGLES, m_render_state, m_scene_state, sr->shader, sr->varray, sr->buffer.get_size() * 6 );
[126]273}
274
275renderer::~renderer()
276{
277        for ( auto p : m_fonts )
278        {
279                delete p;
280        }
[301]281        if ( m_render_data )
282        {
[302]283                m_context->get_device()->release( ((screen_render_data*)m_render_data)->tex );
[301]284                delete m_render_data;
285        }
[126]286}
Note: See TracBrowser for help on using the repository browser.