source: trunk/src/gl/gl_device.cc @ 331

Last change on this file since 331 was 331, checked in by epyon, 11 years ago
  • texture types (1D,2D,Rect,3D,Cube - not all fully supported yet)
  • full framebuffer support
  • fixes to texture support
  • minor fixes
File size: 12.9 KB
RevLine 
[319]1// Copyright (C) 2012-2014 ChaosForge Ltd
[38]2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gl/gl_device.hh"
6
7#include "nv/gl/gl_window.hh"
[319]8#include "nv/core/logging.hh"
[90]9#include "nv/lib/sdl_image.hh"
[301]10#include "nv/gl/gl_enum.hh"
11#include "nv/lib/gl.hh"
[38]12
13using namespace nv;
14
15gl_device::gl_device()
16{
[316]17        m_shader_header  = "#version 120\n";
18        for ( auto& i : get_uniform_factory() )
19                m_shader_header += "uniform "+datatype_to_glsl_type( i.second->get_datatype() )+" "+i.first+";\n";
20        for ( auto& i : get_link_uniform_factory() )
21                m_shader_header += "uniform sampler2D "+i.first+";\n";
[38]22}
23
[303]24program gl_device::create_program( const string& vs_source, const string& fs_source )
[38]25{
[303]26        program result = m_programs.create();
27        gl_program_info* info = m_programs.get( result );
28
29        info->glid = glCreateProgram();
30        compile( info, vs_source, fs_source );
31        prepare_program( result );
32        return result;
[38]33}
34
[90]35// this is a temporary function that will be removed once we find a way to
36// pass binary file data around
[326]37image_data* gl_device::create_image_data( const std::string& filename )
[90]38{
39        load_sdl_image_library();
40        SDL_Surface* image = IMG_Load( filename.c_str() );
[120]41        if (!image)
42        {
43                NV_LOG( LOG_ERROR, "Image file " << filename.c_str() << " not found!" );
44                return nullptr;
45        }
[292]46        // TODO: BGR vs RGB, single channel
47        assert( image->format->BytesPerPixel > 2 );
48        image_format format(image->format->BytesPerPixel == 3 ? RGB : RGBA, UBYTE );
49        image_data* data = new image_data( format, glm::ivec2( image->w, image->h ), (nv::uint8*)image->pixels );
[90]50        return data;
51}
52
[92]53
[38]54gl_device::~gl_device()
55{
[302]56        while ( m_textures.size() > 0 )
57                release( m_textures.get_handle(0) );
58        while ( m_buffers.size() > 0 )
59                release( m_buffers.get_handle(0) );
[303]60        while ( m_programs.size() > 0 )
61                release( m_programs.get_handle(0) );
[38]62}
[301]63
[331]64nv::texture nv::gl_device::create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, void* data /*= nullptr */ )
[301]65{
66        unsigned glid = 0;
[331]67        unsigned gl_type = texture_type_to_enum( type );
[301]68        glGenTextures( 1, &glid );
69
[331]70        glBindTexture( gl_type, glid );
[301]71
72        // Detect if mipmapping was requested
[331]73        if ( gl_type == GL_TEXTURE_2D && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
[301]74        {
[331]75                // TODO: This should not be done if we use framebuffers!
76                glTexParameteri( gl_type, GL_GENERATE_MIPMAP, GL_TRUE);
[301]77        }
78
[331]79        if ( asampler.filter_max != sampler::NEAREST )
[301]80        {
[331]81                asampler.filter_max = sampler::LINEAR;
[301]82        }
83
[331]84        glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_min ) );
85        glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_max ) );
86        glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, (int)nv::sampler_wrap_to_enum( asampler.wrap_s) );
87        glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, (int)nv::sampler_wrap_to_enum( asampler.wrap_t) );
[301]88
[331]89        glTexImage2D( gl_type, 0, (GLint)nv::image_format_to_internal_enum(aformat.format), size.x, size.y, 0, nv::image_format_to_enum(aformat.format), nv::datatype_to_gl_enum(aformat.type), data );
90
91        glBindTexture( gl_type, 0 );
92
[301]93        texture result = m_textures.create();
94        gl_texture_info* info = m_textures.get( result );
[331]95        info->type     = type;
[323]96        info->format   = aformat;
97        info->tsampler = asampler;
98        info->size     = size;
99        info->glid     = glid;
[301]100        return result;
101}
102
[302]103void nv::gl_device::release( texture t )
[301]104{
105        gl_texture_info* info = m_textures.get( t );
106        if ( info )
107        {
[302]108                if ( info->glid != 0 )
109                {
110                        glDeleteTextures( 1, &(info->glid) );
111                }
[301]112                m_textures.destroy( t );
113        }
114}
115
[302]116void nv::gl_device::release( buffer b )
117{
118        gl_buffer_info* info = m_buffers.get( b );
119        if ( info )
120        {
121                if ( info->glid != 0 )
122                {
123                        glDeleteBuffers( 1, &(info->glid) );
124                }
125                m_buffers.destroy( b );
126        }
127}
128
[303]129const texture_info* nv::gl_device::get_texture_info( texture t ) const
[301]130{
131        return m_textures.get( t );
132}
133
[302]134nv::buffer nv::gl_device::create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source /*= nullptr */ )
135{
136        unsigned glid   = 0;
137        unsigned glenum = buffer_type_to_enum( type );
138        glGenBuffers( 1, &glid );
139
140        glBindBuffer( glenum, glid );
141        glBufferData( glenum, (GLsizeiptr)size, source, buffer_hint_to_enum( hint ) );
142        glBindBuffer( glenum, 0 );
143
144        buffer result = m_buffers.create();
145        gl_buffer_info* info = m_buffers.get( result );
146        info->type = type;
147        info->hint = hint;
148        info->size = size;
149        info->glid = glid;
150        return result;
151}
152
[303]153const buffer_info* nv::gl_device::get_buffer_info( buffer t ) const
[302]154{
155        return m_buffers.get( t );
156}
[303]157
158void nv::gl_device::release( program p )
159{
160        gl_program_info* info = m_programs.get( p );
161        if ( info )
162        {
163                for ( auto& i : info->m_uniform_map )
164                        delete i.second;
165
166                glDetachShader( info->glid, info->glidv );
167                glDetachShader( info->glid, info->glidf );
168                glDeleteShader( info->glidv );
169                glDeleteShader( info->glidf );
170                glDeleteProgram( info->glid );
171
172                m_programs.destroy( p );
173        }
174}
175
176void nv::gl_device::prepare_program( program p )
177{
178        gl_program_info* info = m_programs.get( p );
179        if ( info )
180        {
181                auto& map  = get_uniform_factory();
182                auto& lmap = get_link_uniform_factory();
183
184                for ( auto& i : info->m_uniform_map )
185                {
186                        auto j = lmap.find( i.first );
187                        if ( j != lmap.end() )
188                        {
189                                j->second->set( i.second );
190                        }                       
191
192                        auto k = map.find( i.first );
193                        if ( k != map.end() )
194                        {
195                                info->m_engine_uniforms.push_back( k->second->create( i.second ) );
196                        }                               
197                }
198        }
199}
200
201uniform_base* nv::gl_device::get_uniform( program p, const string& name, bool fatal /*= true */ ) const
202{
203        const gl_program_info* info = m_programs.get( p );
204        {
205                uniform_map::const_iterator i = info->m_uniform_map.find( name );
206                if ( i != info->m_uniform_map.end() )
207                {
208                        return i->second;
209                }
210                if ( fatal )
211                {
212                        NV_LOG( LOG_ERROR, "Uniform '" << name << "' not found in program!" );
213                        NV_THROW( runtime_error, ( "Uniform '"+name+"' not found!" ) );
214                }
215        }
216        return nullptr;
217}
218
219int nv::gl_device::get_attribute_location( program p, const string& name, bool fatal /*= true */ ) const
220{
221        const gl_program_info* info = m_programs.get( p );
222        if ( info )
223        {
224                attribute_map::const_iterator i = info->m_attribute_map.find( name );
225                if ( i != info->m_attribute_map.end() )
226                {
227                        return i->second.location;
228                }
229                if ( fatal )
230                {
231                        NV_LOG( LOG_ERROR, "Attribute '" << name << "' not found in program!" );
232                        NV_THROW( runtime_error, ( "Attribute '"+name+"' not found!" ) );
233                }
234        }
235        return -1;
236}
237
238bool nv::gl_device::compile( gl_program_info* p, const string& vertex_program, const string& fragment_program )
239{
240        if (!compile( GL_VERTEX_SHADER,   vertex_program, p->glidv ))   { return false; }
241        if (!compile( GL_FRAGMENT_SHADER, fragment_program, p->glidf )) { return false; }
242
243        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::POSITION   ), "nv_position"  );
244        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::TEXCOORD   ), "nv_texcoord"  );
245        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::NORMAL     ), "nv_normal"    );
246        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::COLOR      ), "nv_color"     );
247        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::TANGENT    ), "nv_tangent"   );
248        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEINDEX  ), "nv_boneindex" );
249        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEWEIGHT ), "nv_boneweight");
250
251        glAttachShader( p->glid, p->glidf );
252        glAttachShader( p->glid, p->glidv );
253        glLinkProgram( p->glid );
254
255        const uint32 buffer_size = 2048;
256        char buffer[ buffer_size ] = { 0 };
257        int length;
258        int status;
259
260        glGetProgramiv( p->glid, GL_LINK_STATUS, &status );
261        glGetProgramInfoLog( p->glid, buffer_size, &length, buffer );
262
263        NV_LOG( LOG_INFO, "Program #" << p->glid << (status == GL_FALSE ? " failed to compile!" : " compiled successfully.") );
264
265        if ( length > 0 )
266        {
267                NV_LOG( LOG_INFO, "Program #" << p->glid << " log: " << buffer );
268        }
269
270        if ( status == GL_FALSE )
271        {
272                return false;
273        }
274
275        glValidateProgram( p->glid );
276        glGetProgramiv( p->glid, GL_VALIDATE_STATUS, &status );
277
278        if ( status == GL_FALSE )
279        {
280                glGetProgramInfoLog( p->glid, buffer_size, &length, buffer );
281                NV_LOG( LOG_ERROR, "Program #" << p->glid << " validation error : " << buffer );
282                return false;
283        }
284        load_attributes( p );
285        load_uniforms( p );
286        return true;
287}
288
289void nv::gl_device::update_uniforms( gl_program_info* p )
290{
291        for ( uniform_map::iterator i = p->m_uniform_map.begin();       i != p->m_uniform_map.end(); ++i )
292        {
293                uniform_base* ubase = i->second;
294                if ( ubase->is_dirty() )
295                {
296                        int uloc = ubase->get_location();
297                        switch( ubase->get_type() )
298                        {
299                        case FLOAT          : glUniform1fv( uloc, ubase->get_length(), ((uniform< enum_to_type< FLOAT >::type >*)( ubase ))->get_value() ); break;
300                        case INT            : glUniform1iv( uloc, ubase->get_length(), ((uniform< enum_to_type< INT >::type >*)( ubase ))->get_value() ); break;
301                        case FLOAT_VECTOR_2 : glUniform2fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
302                        case FLOAT_VECTOR_3 : glUniform3fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
303                        case FLOAT_VECTOR_4 : glUniform4fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
304                        case INT_VECTOR_2   : glUniform2iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
305                        case INT_VECTOR_3   : glUniform3iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
306                        case INT_VECTOR_4   : glUniform4iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
307                        case FLOAT_MATRIX_2 : glUniformMatrix2fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_2 >::type >*)( ubase ))->get_value()); break;
308                        case FLOAT_MATRIX_3 : glUniformMatrix3fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_3 >::type >*)( ubase ))->get_value()); break;
309                        case FLOAT_MATRIX_4 : glUniformMatrix4fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_4 >::type >*)( ubase ))->get_value()); break;
310                        default : break; // error?
311                        }
312                        ubase->clean();
313                }
314        }
315}
316
317void nv::gl_device::load_attributes( gl_program_info* p )
318{
319        int params;
320        glGetProgramiv( p->glid, GL_ACTIVE_ATTRIBUTES, &params );
321
322        for ( unsigned i = 0; i < (unsigned)params; ++i )
323        {
324                int attr_nlen;
325                int attr_len;
326                unsigned attr_type;
327                char name_buffer[128];
328
329                glGetActiveAttrib( p->glid, i, 128, &attr_nlen, &attr_len, &attr_type, name_buffer );
330
331                string name( name_buffer, size_t(attr_nlen) );
332
333                // skip built-ins
334                if ( name.substr(0,3) == "gl_" ) continue;
335
336                int attr_loc = glGetAttribLocation( p->glid, name.c_str() );
337
338                attribute& attr = p->m_attribute_map[ name ];
339                attr.name     = name;
340                attr.location = attr_loc;
341                attr.type     = gl_enum_to_datatype( attr_type );
342                attr.length   = attr_len;
343        }
344}
345
346void nv::gl_device::load_uniforms( gl_program_info* p )
347{
348        int params;
349        glGetProgramiv( p->glid, GL_ACTIVE_UNIFORMS, &params );
350
351        for ( unsigned i = 0; i < size_t(params); ++i )
352        {
353                int uni_nlen;
354                int uni_len;
355                unsigned uni_type;
356                char name_buffer[128];
357
358                glGetActiveUniform( p->glid, i, 128, &uni_nlen, &uni_len, &uni_type, name_buffer );
359
360                string name( name_buffer, size_t(uni_nlen) );
361
362                // skip built-ins
363                if ( name.substr(0,3) == "gl_" ) continue;
364
365                int uni_loc = glGetUniformLocation( p->glid, name.c_str() );
366                datatype utype = gl_enum_to_datatype( uni_type );
367
368                // check for array
369                string::size_type arrchar = name.find('[');
370                if ( arrchar != string::npos )
371                {
372                        name = name.substr( 0, arrchar );
373                }
374
375                uniform_base* u = uniform_base::create( utype, name, uni_loc, uni_len );
376                NV_ASSERT( u, "Unknown uniform type!" );
377                p->m_uniform_map[ name ] = u;
378        }
379}
380
381bool nv::gl_device::compile( uint32 sh_type, const std::string& shader_code, unsigned& glid )
382{
383        glid = glCreateShader( sh_type );
384
385        const char* pc = shader_code.c_str();
386
387        glShaderSource( glid,   1, &pc, 0 );
388        glCompileShader( glid );
389
390        const uint32 buffer_size = 1024;
391        char buffer[ buffer_size ] = { 0 };
392        int length;
393        int compile_ok = GL_FALSE;
394        glGetShaderiv(glid, GL_COMPILE_STATUS, &compile_ok);
395        glGetShaderInfoLog( glid, buffer_size, &length, buffer );
396
397        if ( length > 0 )
398        {
399                if ( compile_ok == 0 )
400                {
401                        NV_LOG( LOG_ERROR, "Shader #" << glid << " error: " << buffer );
402                }
403                else
404                {
405                        NV_LOG( LOG_INFO, "Shader #" << glid << " compiled successfully: " << buffer );
406                }
407        }
408        else
409        {
410                NV_LOG( LOG_INFO, "Shader #" << glid << " compiled successfully." );
411        }
412        return compile_ok != 0;
413
414}
415
Note: See TracBrowser for help on using the repository browser.