source: trunk/src/gl/gl_program.cc @ 243

Last change on this file since 243 was 237, checked in by epyon, 11 years ago
  • debug_draw module added
  • evil vertex descriptor and info added
  • fix for sampler objects
  • various fixes
File size: 8.1 KB
Line 
1// Copyright (C) 2012-2013 Kornel Kisielewicz
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_program.hh"
6
7#include "nv/gl/gl_enum.hh"
8#include "nv/logging.hh"
9#include "nv/lib/gl.hh"
10
11#include <glm/glm.hpp>
12#include <glm/gtc/type_ptr.hpp>
13
14using namespace nv;
15
16gl_shader::gl_shader( uint32 sh_type )
17        : shader_type( sh_type ), object_id(0)
18{
19        // no op
20}
21
22gl_shader::gl_shader( uint32 sh_type, const string& shader_code )
23        : shader_type( sh_type ), object_id(0)
24{
25        compile( shader_code );
26}
27
28gl_shader::~gl_shader()
29{
30        free();
31}
32
33bool gl_shader::compile( const string& shader_code )
34{
35        generate();
36
37        const char* pc = shader_code.c_str();
38
39        glShaderSource( object_id,   1, &pc, 0 );
40        glCompileShader( object_id );
41
42        return validate();
43}
44
45void gl_shader::generate()
46{
47        if ( is_valid() )
48        {
49                free();
50        }
51        object_id = glCreateShader( shader_type );
52}
53
54void gl_shader::free()
55{
56        glDeleteShader( object_id );
57        object_id = 0;
58}
59
60bool gl_shader::validate()
61{
62        const uint32 buffer_size = 1024;
63        char buffer[ buffer_size ] = { 0 };
64        int length;
65        int compile_ok = GL_FALSE;
66        glGetShaderiv(object_id, GL_COMPILE_STATUS, &compile_ok);
67        glGetShaderInfoLog( object_id, buffer_size, &length, buffer );
68
69        if ( length > 0 )
70        {
71                if ( compile_ok == 0 )
72                {
73                        NV_LOG( LOG_ERROR, "Shader #" << object_id << " error: " << buffer );
74                }
75                else
76                {
77                        NV_LOG( LOG_INFO, "Shader #" << object_id << " compiled successfully: " << buffer );
78                }
79        }
80        else
81        {
82                NV_LOG( LOG_INFO, "Shader #" << object_id << " compiled successfully." );
83        }
84        return compile_ok != 0;
85}
86
87gl_program::gl_program( const string& vertex_program, const string& fragment_program )
88        : vertex_shader( GL_VERTEX_SHADER ), fragment_shader( GL_FRAGMENT_SHADER )
89{
90        compile( vertex_program, fragment_program );
91}
92
93gl_program::~gl_program()
94{
95        if ( is_valid() )
96        {
97                // Detach the shaders from the program
98                glDetachShader( m_name.get_value(), vertex_shader.get_id() );
99                glDetachShader( m_name.get_value(), fragment_shader.get_id() );
100        }
101}
102
103bool gl_program::compile( const string& vertex_program, const string& fragment_program )
104{
105        if (!vertex_shader.compile( vertex_program )) { return false; }
106        if (!fragment_shader.compile( fragment_program )) { return false; }
107
108        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::POSITION   ), "nv_position"  );
109        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::TEXCOORD   ), "nv_texcoord"  );
110        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::NORMAL     ), "nv_normal"    );
111        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::COLOR      ), "nv_color"     );
112        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::TANGENT    ), "nv_tangent"   );
113        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::BONEINDEX  ), "nv_boneindex" );
114        glBindAttribLocation( m_name.get_value(), static_cast<GLuint>( slot::BONEWEIGHT ), "nv_boneweight");
115
116        glAttachShader( m_name.get_value(), fragment_shader.get_id() );
117        glAttachShader( m_name.get_value(), vertex_shader.get_id() );
118        glLinkProgram( m_name.get_value() );
119
120        if (!validate())
121        {
122                return false;
123        }
124        load_attributes();
125        load_uniforms();
126        return true;
127}
128
129void gl_program::bind()
130{
131        glUseProgram( m_name.get_value() );
132        update_uniforms();
133}
134
135void gl_program::unbind()
136{
137        glUseProgram( 0 );
138}
139
140bool gl_program::is_valid() const
141{
142        return m_name.is_valid();
143}
144
145void gl_program::load_attributes()
146{
147        int params;
148        glGetProgramiv( m_name.get_value(), GL_ACTIVE_ATTRIBUTES, &params );
149
150        for ( unsigned i = 0; i < (unsigned)params; ++i )
151        {
152                int attr_nlen;
153                int attr_len;
154                unsigned attr_type;
155                char name_buffer[128];
156
157                glGetActiveAttrib( m_name.get_value(), i, 128, &attr_nlen, &attr_len, &attr_type, name_buffer );
158
159                string name( name_buffer, size_t(attr_nlen) );
160
161                // skip built-ins
162                if ( name.substr(0,3) == "gl_" ) continue;
163
164                int attr_loc = glGetAttribLocation( m_name.get_value(), name.c_str() );
165
166                m_attribute_map[ name ] = new attribute( name, attr_loc, gl_enum_to_datatype( attr_type ), attr_len );
167        }
168}
169
170void gl_program::load_uniforms()
171{
172        int params;
173        glGetProgramiv( m_name.get_value(), GL_ACTIVE_UNIFORMS, &params );
174
175        for ( unsigned i = 0; i < size_t(params); ++i )
176        {
177                int uni_nlen;
178                int uni_len;
179                unsigned uni_type;
180                char name_buffer[128];
181
182                glGetActiveUniform( m_name.get_value(), i, 128, &uni_nlen, &uni_len, &uni_type, name_buffer );
183
184                string name( name_buffer, size_t(uni_nlen) );
185               
186                // skip built-ins
187                if ( name.substr(0,3) == "gl_" ) continue;
188
189                int uni_loc = glGetUniformLocation( m_name.get_value(), name.c_str() );
190                datatype utype = gl_enum_to_datatype( uni_type );
191               
192                // check for array
193                string::size_type arrchar = name.find('[');
194                if ( arrchar != string::npos )
195                {
196                        name = name.substr( 0, arrchar );
197                }
198
199                uniform_base* u = create_uniform( utype, name, uni_loc, uni_len );
200                NV_ASSERT( u, "Unknown uniform type!" );
201                m_uniform_map[ name ] = u;
202        }
203
204        apply_link_engine_uniforms();
205        bind_engine_uniforms();
206}
207
208void gl_program::update_uniforms()
209{
210        for ( uniform_map::iterator i = m_uniform_map.begin();  i != m_uniform_map.end(); ++i )
211        {
212                uniform_base* ubase = i->second;
213                if ( ubase->is_dirty() )
214                {
215                        int uloc = ubase->get_location();
216                        switch( ubase->get_type() )
217                        {
218                        case FLOAT          : glUniform1fv( uloc, ubase->get_length(), ((uniform< enum_to_type< FLOAT >::type >*)( ubase ))->get_value() ); break;
219                        case INT            : glUniform1iv( uloc, ubase->get_length(), ((uniform< enum_to_type< INT >::type >*)( ubase ))->get_value() ); break;
220                        case FLOAT_VECTOR_2 : glUniform2fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
221                        case FLOAT_VECTOR_3 : glUniform3fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
222                        case FLOAT_VECTOR_4 : glUniform4fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
223                        case INT_VECTOR_2   : glUniform2iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
224                        case INT_VECTOR_3   : glUniform3iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
225                        case INT_VECTOR_4   : glUniform4iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
226                        case FLOAT_MATRIX_2 : glUniformMatrix2fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_2 >::type >*)( ubase ))->get_value()); break;
227                        case FLOAT_MATRIX_3 : glUniformMatrix3fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_3 >::type >*)( ubase ))->get_value()); break;
228                        case FLOAT_MATRIX_4 : glUniformMatrix4fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_4 >::type >*)( ubase ))->get_value()); break;
229                        default : break; // error?
230                        }
231                        ubase->clean();
232                }
233        }
234
235}
236
237
238bool gl_program::validate()
239{
240        const uint32 buffer_size = 2048;
241        char buffer[ buffer_size ] = { 0 };
242        int length;
243        int status;
244
245        glGetProgramiv( m_name.get_value(), GL_LINK_STATUS, &status );
246        glGetProgramInfoLog( m_name.get_value(), buffer_size, &length, buffer );
247
248        NV_LOG( LOG_INFO, "Program #" << m_name.get_value() << (status == GL_FALSE ? " failed to compile!" : " compiled successfully.") );
249
250        if ( length > 0 )
251        {
252                NV_LOG( LOG_INFO, "Program #" << m_name.get_value() << " log: " << buffer );
253        }
254
255        if ( status == GL_FALSE )
256        {
257                return false;
258        }
259
260        glValidateProgram( m_name.get_value() );
261        glGetProgramiv( m_name.get_value(), GL_VALIDATE_STATUS, &status );
262
263        if ( status == GL_FALSE )
264        {
265                glGetProgramInfoLog( m_name.get_value(), buffer_size, &length, buffer );
266                NV_LOG( LOG_ERROR, "Program #" << m_name.get_value() << " validation error : " << buffer );
267                return false;
268        }
269        return true;
270}
271
272
Note: See TracBrowser for help on using the repository browser.