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

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