1 #include "Shader.h"
2 #include <fstream>
3 #include <string>
4 #include <iostream>
5 
6 
7 
8 
Allocate()9 bool GPU::Shader::PgObject::Allocate()
10 {
11     m_Id = glCreateShaderObjectARB( m_PgType );
12     return m_Id != 0;
13 }
14 
15 
Unallocate()16 bool GPU::Shader::PgObject::Unallocate()
17 {
18     glDeleteObjectARB( m_Id );
19     m_Id = 0;
20     return true;
21 }
22 
23 
CompileSrcFile(const std::string & filename,const GLenum pgType,std::string * logs)24 bool GPU::Shader::PgObject::CompileSrcFile( const std::string &filename,
25                                             const GLenum pgType,
26                                             std::string *logs )
27 {
28     // Open the source files.
29 	std::ifstream file( filename.c_str(), std::ios::binary );
30     if( file.fail() )
31         return false;
32 
33 	// Map the content of the shader source file into a memory buffer.
34     file.seekg( 0, std::ios::end );
35 	int fileSize = (int) file.tellg();
36 	file.seekg( 0, std::ios::beg );
37 
38 	char *sourceString = new char [ fileSize+1 ];
39 	file.read( sourceString, fileSize );
40 	sourceString[ fileSize ] = '\0';
41 
42     file.close();
43 
44 	// Create the shader object.
45     bool ok = CompileSrcString( sourceString, pgType, logs );
46 
47     // Termination.
48     delete [] sourceString;
49     return ok;
50 }
51 
52 
CompileSrcString(const char * sourceString,const GLenum pgType,std::string * logs)53 bool GPU::Shader::PgObject::CompileSrcString( const char *sourceString,
54                                               const GLenum pgType,
55                                               std::string *logs )
56 {
57     // Ask for a free shader object name to OpenGL.
58     m_PgType = pgType;
59     if( Instantiate() )
60     {
61         // Create the shader object.
62 	    glShaderSourceARB ( m_Id, 1, (const GLcharARB**) &sourceString, NULL );
63 	    glCompileShaderARB( m_Id );
64 
65         // Check the compilation status.
66 	    GLint status;
67         glGetObjectParameterivARB( m_Id, GL_OBJECT_COMPILE_STATUS_ARB, &status );
68 
69         if( status )
70             return true;
71         else if( logs )
72             *logs = GPU::Shader::GetLogs( m_Id );
73 
74         Release();
75     }
76 
77     return false;
78 }
79 
80 
81 
82 
GetLogs(GLuint pgId)83 std::string GPU::Shader::GetLogs( GLuint pgId )
84 {
85     GLint logLength;
86     glGetObjectParameterivARB( pgId, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength );
87 
88     std::string infoLog;
89     infoLog.resize( logLength );
90     glGetInfoLogARB( pgId, logLength, &logLength, &infoLog[0] );
91 
92     return infoLog;
93 }
94 
95 
RecoverActiveUniforms()96 void GPU::Shader::RecoverActiveUniforms()
97 {
98     m_Uniforms.clear();
99     m_Samplers.clear();
100 
101 	GLint count;
102 	GLcharARB nameBuffer[512];
103 
104     glGetObjectParameterivARB( m_Id, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count );
105 
106 	for( GLint i=0; i<count; ++i )
107 	{
108 		GLsizei length;
109         GLint   size;
110         GLenum  type;
111 
112 		glGetActiveUniformARB(
113             m_Id,
114             i,
115             sizeof(nameBuffer),
116             &length,
117             &size,
118             &type,
119             nameBuffer
120             );
121 
122 		std::string name( nameBuffer );
123 
124         if( type<GL_SAMPLER_1D_ARB || type>GL_SAMPLER_2D_RECT_SHADOW_ARB )
125         {
126             m_Uniforms[name].location = glGetUniformLocationARB( m_Id, nameBuffer );
127 		    m_Uniforms[name].size = size;
128 		    m_Uniforms[name].type = type;
129         }
130         else
131             m_Samplers[name] = glGetUniformLocationARB( m_Id, nameBuffer );
132     }
133 }
134 
135 
RecoverActiveAttributes()136 void GPU::Shader::RecoverActiveAttributes()
137 {
138     m_Attributes.clear();
139 
140     GLint count;
141 	GLcharARB nameBuffer[512];
142 
143 	glGetObjectParameterivARB( m_Id, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &count );
144 
145 	for( GLint i=0; i<count; ++i )
146 	{
147 		GLsizei length;
148         GLint   size;
149         GLenum  type;
150 
151 		glGetActiveAttribARB(
152             m_Id,
153             i,
154             sizeof(nameBuffer),
155             &length,
156             &size,
157             &type,
158             nameBuffer
159             );
160 
161 		GLint attribId = glGetAttribLocationARB( m_Id, nameBuffer );
162 		if( attribId != -1 )
163             m_Attributes[ std::string(nameBuffer) ] = attribId;
164 	}
165 }
166 
167 
Link(std::string * logs)168 bool GPU::Shader::Link( std::string *logs )
169 {
170     if( !m_Id && !(m_Id = glCreateProgramObjectARB()) )
171         return false;
172 
173 
174     if( m_VertPg.IsInstantiated() )
175         glAttachObjectARB( m_Id, m_VertPg.Id() );
176 
177     if( m_FragPg.IsInstantiated() )
178         glAttachObjectARB( m_Id, m_FragPg.Id() );
179 
180     if( m_GeomPg.IsInstantiated() )
181         glAttachObjectARB( m_Id, m_GeomPg.Id() );
182 
183     glLinkProgramARB( m_Id );
184 
185     GLint status;
186     glGetObjectParameterivARB( m_Id, GL_OBJECT_LINK_STATUS_ARB, &status );
187     if( !status )
188     {
189         if( logs )
190             *logs = GetLogs( m_Id );
191 
192         glDeleteObjectARB( m_Id );
193         m_Id = 0;
194 
195         return false;
196     }
197 
198 
199     RecoverActiveUniforms();
200     RecoverActiveAttributes();
201 
202     return true;
203 }
204 
205 
206 
Attach(const PgObject & pg)207 GPU::Shader& GPU::Shader::Attach( const PgObject &pg )
208 {
209     PgObject *dst = NULL;
210 
211     switch( pg.Type() )
212     {
213         case GL_VERTEX_SHADER_ARB:   dst = &m_VertPg; break;
214         case GL_FRAGMENT_SHADER_ARB: dst = &m_FragPg; break;
215         case GL_GEOMETRY_SHADER_EXT: dst = &m_GeomPg; break;
216     }
217 
218     if( dst )
219     {
220         if( m_Id && dst->IsInstantiated() )
221             glDetachObjectARB( m_Id, dst->Id() );
222         *dst = pg;
223     }
224 
225     return *this;
226 }
227 
228 
DetachVertPg()229 GPU::Shader& GPU::Shader::DetachVertPg()
230 {
231     if( m_Id && m_VertPg.IsInstantiated() )
232         glDetachObjectARB( m_Id, m_VertPg.Id() );
233     m_VertPg.Release();
234     return *this;
235 }
236 
237 
DetachFragPg()238 GPU::Shader& GPU::Shader::DetachFragPg()
239 {
240     if( m_Id && m_FragPg.IsInstantiated() )
241         glDetachObjectARB( m_Id, m_FragPg.Id() );
242     m_FragPg.Release();
243     return *this;
244 }
245 
246 
DetachGeomPg()247 GPU::Shader& GPU::Shader::DetachGeomPg()
248 {
249     if( m_Id && m_GeomPg.IsInstantiated() )
250         glDetachObjectARB( m_Id, m_GeomPg.Id() );
251     m_GeomPg.Release();
252     return *this;
253 }
254 
255 
256 /*
257 bool GPU::Shader::CreateFromFiles( const std::string &vshFilename,
258                                    const std::string &fshFilename )
259 {
260     VertPg vsh;
261     FragPg fsh;
262 
263     return vsh.LoadFile( vshFilename ) &&
264            fsh.LoadFile( fshFilename ) &&
265            Create( vsh, fsh );
266 }
267 
268 
269 bool GPU::Shader::CreateFromSources( const char *vshSourceStr,
270                                      const char *fshSourceStr )
271 {
272     VertPg vsh;
273     FragPg fsh;
274 
275     return vsh.LoadSource( vshSourceStr ) &&
276            fsh.LoadSource( fshSourceStr ) &&
277            Create( vsh, fsh );
278 }
279 */
280 
281 
Release()282 void GPU::Shader::Release()
283 {
284     if( m_Id )
285     {
286         if( m_VertPg.Id() )
287         {
288             glDetachObjectARB( m_Id, m_VertPg.Id() );
289             m_VertPg.Release();
290         }
291         if( m_FragPg.Id() )
292         {
293             glDetachObjectARB( m_Id, m_FragPg.Id() );
294             m_FragPg.Release();
295         }
296         if( m_GeomPg.Id() )
297         {
298             glDetachObjectARB( m_Id, m_GeomPg.Id() );
299             m_GeomPg.Release();
300         }
301 
302         glDeleteObjectARB( m_Id );
303         m_Id = 0;
304 
305         m_Uniforms.clear();
306         m_Attributes.clear();
307     }
308 }
309 
310 
SetUniform(const std::string & name,const void * value)311 void GPU::Shader::SetUniform( const std::string& name,
312                               const void *value )
313 {
314     UniformMap::iterator uu = m_Uniforms.find( name );
315     if( uu != m_Uniforms.end() )
316     {
317 	    GLuint activeProgBackup = glGetHandleARB( GL_PROGRAM_OBJECT_ARB );
318 	    glUseProgramObjectARB( m_Id );
319 
320         Uniform &u = uu->second;
321 	    switch( u.type )
322 	    {
323 		    case GL_FLOAT:          glUniform1fvARB( u.location, u.size, (GLfloat*) value ); break;
324 		    case GL_FLOAT_VEC2_ARB: glUniform2fvARB( u.location, u.size, (GLfloat*) value ); break;
325 		    case GL_FLOAT_VEC3_ARB: glUniform3fvARB( u.location, u.size, (GLfloat*) value ); break;
326 		    case GL_FLOAT_VEC4_ARB: glUniform4fvARB( u.location, u.size, (GLfloat*) value ); break;
327 		    case GL_INT:            glUniform1ivARB( u.location, u.size, (GLint*) value ); break;
328 		    case GL_INT_VEC2_ARB:   glUniform2ivARB( u.location, u.size, (GLint*) value ); break;
329 		    case GL_INT_VEC3_ARB:   glUniform3ivARB( u.location, u.size, (GLint*) value ); break;
330 		    case GL_INT_VEC4_ARB:   glUniform4ivARB( u.location, u.size, (GLint*) value ); break;
331 		    case GL_BOOL_ARB:       glUniform1ivARB( u.location, u.size, (GLint*) value ); break;
332 		    case GL_BOOL_VEC2_ARB:  glUniform2ivARB( u.location, u.size, (GLint*) value ); break;
333 		    case GL_BOOL_VEC3_ARB:  glUniform3ivARB( u.location, u.size, (GLint*) value ); break;
334 		    case GL_BOOL_VEC4_ARB:  glUniform4ivARB( u.location, u.size, (GLint*) value ); break;
335 		    case GL_FLOAT_MAT2_ARB: glUniformMatrix2fvARB( u.location, u.size, GL_FALSE, (GLfloat*) value ); break;
336 		    case GL_FLOAT_MAT3_ARB: glUniformMatrix3fvARB( u.location, u.size, GL_FALSE, (GLfloat*) value ); break;
337 		    case GL_FLOAT_MAT4_ARB: glUniformMatrix4fvARB( u.location, u.size, GL_FALSE, (GLfloat*) value ); break;
338 	    }
339 
340 	    glUseProgramObjectARB( activeProgBackup );
341     }
342 }
343 
344 
SetSampler(const std::string & name,const GLint texUnit)345 void GPU::Shader::SetSampler( const std::string& name,
346                               const GLint texUnit )
347 {
348     SamplerMap::iterator s = m_Samplers.find( name );
349     if( s != m_Samplers.end() )
350     {
351 	    GLuint activeProgBackup = glGetHandleARB( GL_PROGRAM_OBJECT_ARB );
352 	    glUseProgramObjectARB( m_Id );
353 
354         glUniform1iARB( s->second, texUnit );
355 
356 	    glUseProgramObjectARB( activeProgBackup );
357     }
358 }
359