CSCI441 OpenGL Library 5.13.0
CS@Mines CSCI441 Computer Graphics Course Library
Loading...
Searching...
No Matches
ShaderUtils.hpp
Go to the documentation of this file.
1
14#ifndef CSCI441_SHADER_UTILS_HPP
15#define CSCI441_SHADER_UTILS_HPP
16
17#ifdef CSCI441_USE_GLEW
18 #include <GL/glew.h>
19#else
20 #include <glad/gl.h>
21#endif
22
23#include <cstdio>
24#include <cstring>
25#include <fstream>
26#include <string>
27
28//********************************************************************************************************************
29
30namespace CSCI441_INTERNAL::ShaderUtils {
31 static bool sDEBUG = true;
32
33 // Enables console output
34 [[maybe_unused]] void enableDebugMessages();
35
36 // Disables console output
37 [[maybe_unused]] void disableDebugMessages();
38
39 // Converts a GLenum data type variable to the string name of the associated value
40 // GLenum data type
41 // const char* name of data type
42 const char* GLSL_type_to_string( GLenum type );
43
44 // Converts a GLenum shader type variable to the string name of the associated value
45 // GLenum shader type
46 // const char* name of shader type
47 const char* GL_shader_type_to_string( GLenum type );
48
49 // Converts a GLenum primitive type variable to the string name of the associated value
50 // GLenum primitive type
51 // const char* name of primitive type
52 const char* GL_primitive_type_to_string( GLenum type );
53
54 // Reads the contents of a text file to a character array
55 // const char* filename of shader file to read in
56 // char*& character array to store the contents of the file. Will allocate memory and populate within the function
57 // bool true if file was successfully opened and read. false otherwise
58 bool readTextFromFile( const char* filename, GLchar* &output );
59
60 // Reads the contents of a text file and compiles the associated shader type
61 // const char* filename of shader file to read in
62 // GLenum type of shader file corresponds to
63 // GLuint shader handle if compilation successful. -1 otherwise
64 GLuint compileShader( const char *filename, GLenum shaderType );
65
66 // Prints the shader log for the associated Shader handle
67 void printShaderLog( GLuint shaderHandle );
68
69 // Prints the shader log for the associated Shader Program handle
70 void printProgramLog( GLuint programHandle );
71
72 // Prints the shader log for the associated Program Pipeline handle
73 void printProgramPipelineLog( GLuint pipelineHandle );
74
75 // Prints subroutine information from a Shader program
76 // GLuint Shader Program handle to inspect
77 // GLenum Shader Stage to inspect
78 // GLboolean if opening output line should be printed to console
79 GLboolean printSubroutineInfo(GLuint programHandle, GLenum shaderStage, GLboolean printHeader );
80
81 // Uses Shader Program introspection to print contents of Shader Program
82 // GLuint Shader Program handle to inspect
83 // GLboolean if Shader Program contains a vertex shader
84 // GLboolean if Shader Program contains a tessellation control shader
85 // GLboolean if Shader Program contains a tessellation evaluation shader
86 // GLboolean if Shader Program contains a geometry shader
87 // GLboolean if Shader Program contains a fragment shader
88 // GLboolean if Shader Program contains a compute shader
89 // GLboolean if closing output line should be printed to console (defaults to true)
90 void printShaderProgramInfo( GLuint programHandle,
91 GLboolean hasVertexShader,
92 GLboolean hasTessControlShader, GLboolean hasTessEvalShader,
93 GLboolean hasGeometryShader,
94 GLboolean hasFragmentShader,
95 GLboolean hasComputeShader,
96 GLboolean useLastNewLine );
97}
98
99//********************************************************************************************************************
100
101[[maybe_unused]]
102inline void CSCI441_INTERNAL::ShaderUtils::enableDebugMessages() {
103 sDEBUG = true;
104}
105
106[[maybe_unused]]
107inline void CSCI441_INTERNAL::ShaderUtils::disableDebugMessages() {
108 sDEBUG = false;
109}
110
111//********************************************************************************************************************
112
113inline bool CSCI441_INTERNAL::ShaderUtils::readTextFromFile(
114 const char *filename,
115 GLchar* &output
116){
117 std::string buf = std::string("");
118 std::string line;
119
120 std::ifstream in(filename);
121 if( !in.is_open() ) {
122 fprintf( stderr, "[ERROR]: Could not open file %s\n", filename );
123 return false;
124 }
125 while( std::getline(in, line) ) {
126 buf += line + "\n";
127 }
128
129 output = new GLchar[buf.length()+1];
130 strncpy(output, buf.c_str(), buf.length());
131 output[buf.length()] = '\0';
132
133 in.close();
134
135 return true;
136}
137
138inline const char* CSCI441_INTERNAL::ShaderUtils::GLSL_type_to_string(
139 const GLenum type
140) {
141 switch(type) {
142 case GL_FLOAT: return "float";
143 case GL_FLOAT_VEC2: return "vec2";
144 case GL_FLOAT_VEC3: return "vec3";
145 case GL_FLOAT_VEC4: return "vec4";
146 case GL_DOUBLE: return "double";
147 case GL_DOUBLE_VEC2: return "dvec2";
148 case GL_DOUBLE_VEC3: return "dvec3";
149 case GL_DOUBLE_VEC4: return "dvec4";
150 case GL_INT: return "int";
151 case GL_INT_VEC2: return "ivec2";
152 case GL_INT_VEC3: return "ivec3";
153 case GL_INT_VEC4: return "ivec4";
154 case GL_UNSIGNED_INT: return "unsigned int";
155 case GL_UNSIGNED_INT_VEC2: return "uvec2";
156 case GL_UNSIGNED_INT_VEC3: return "uvec3";
157 case GL_UNSIGNED_INT_VEC4: return "uvec4";
158 case GL_BOOL: return "bool";
159 case GL_BOOL_VEC2: return "bvec2";
160 case GL_BOOL_VEC3: return "bvec3";
161 case GL_BOOL_VEC4: return "bvec4";
162 case GL_FLOAT_MAT2: return "mat2";
163 case GL_FLOAT_MAT3: return "mat3";
164 case GL_FLOAT_MAT4: return "mat4";
165 case GL_FLOAT_MAT2x3: return "mat2x3";
166 case GL_FLOAT_MAT2x4: return "mat2x4";
167 case GL_FLOAT_MAT3x2: return "mat3x2";
168 case GL_FLOAT_MAT3x4: return "mat3x4";
169 case GL_FLOAT_MAT4x2: return "mat4x2";
170 case GL_FLOAT_MAT4x3: return "mat4x3";
171 case GL_DOUBLE_MAT2: return "dmat2";
172 case GL_DOUBLE_MAT3: return "dmat3";
173 case GL_DOUBLE_MAT4: return "dmat4";
174 case GL_DOUBLE_MAT2x3: return "dmat2x3";
175 case GL_DOUBLE_MAT2x4: return "dmat2x4";
176 case GL_DOUBLE_MAT3x2: return "dmat3x2";
177 case GL_DOUBLE_MAT3x4: return "dmat3x4";
178 case GL_DOUBLE_MAT4x2: return "dmat4x2";
179 case GL_DOUBLE_MAT4x3: return "dmat4x3";
180 case GL_SAMPLER_1D: return "sampler1D";
181 case GL_SAMPLER_2D: return "sampler2D";
182 case GL_SAMPLER_3D: return "sampler3D";
183 case GL_SAMPLER_CUBE: return "samplerCube";
184 case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow";
185 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
186 case GL_SAMPLER_1D_ARRAY: return "sampler1DArray";
187 case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
188 case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS";
189 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray";
190 case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
191 case GL_SAMPLER_BUFFER: return "samplerBuffer";
192 case GL_SAMPLER_2D_RECT: return "sampler2DRect";
193 case GL_SAMPLER_2D_RECT_SHADOW: return "sampler2DRectShadow";
194 case GL_INT_SAMPLER_1D: return "isampler1D";
195 case GL_INT_SAMPLER_2D: return "isampler2D";
196 case GL_INT_SAMPLER_3D: return "isampler3D";
197 case GL_INT_SAMPLER_CUBE: return "isamplerCube";
198 case GL_INT_SAMPLER_1D_ARRAY: return "isampler1DArray";
199 case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray";
200 case GL_INT_SAMPLER_2D_MULTISAMPLE: return "isampler2DMS";
201 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "isampler2DMSArray";
202 case GL_INT_SAMPLER_BUFFER: return "isamplerBuffer";
203 case GL_INT_SAMPLER_2D_RECT: return "isampler2DRect";
204 case GL_UNSIGNED_INT_SAMPLER_1D: return "usampler1D";
205 case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D";
206 case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D";
207 case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube";
208 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return "usampler1DArray";
209 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray";
210 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return "usampler2DMS";
211 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray";
212 case GL_UNSIGNED_INT_SAMPLER_BUFFER: return "usamplerBuffer";
213 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return "usampler2DRect";
214 case GL_IMAGE_1D: return "image1D";
215 case GL_IMAGE_2D: return "image2D";
216 case GL_IMAGE_3D: return "image3D";
217 case GL_IMAGE_2D_RECT: return "image2DRect";
218 case GL_IMAGE_CUBE: return "imageCube";
219 case GL_IMAGE_BUFFER: return "imageBuffer";
220 case GL_IMAGE_1D_ARRAY: return "image1DArray";
221 case GL_IMAGE_2D_ARRAY: return "image2DArray";
222 case GL_IMAGE_2D_MULTISAMPLE: return "image2DMS";
223 case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return "image2DMSArray";
224 case GL_INT_IMAGE_1D: return "iimage1D";
225 case GL_INT_IMAGE_2D: return "iimage2D";
226 case GL_INT_IMAGE_3D: return "iimage3D";
227 case GL_INT_IMAGE_2D_RECT: return "iimage2DRect";
228 case GL_INT_IMAGE_CUBE: return "iimageCube";
229 case GL_INT_IMAGE_BUFFER: return "iimageBuffer";
230 case GL_INT_IMAGE_1D_ARRAY: return "iimage1DArray";
231 case GL_INT_IMAGE_2D_ARRAY: return "iimage2DArray";
232 case GL_INT_IMAGE_2D_MULTISAMPLE: return "iimage2DMS";
233 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "iimage2DMSArray";
234 case GL_UNSIGNED_INT_IMAGE_1D: return "uimage1D";
235 case GL_UNSIGNED_INT_IMAGE_2D: return "uimage2D";
236 case GL_UNSIGNED_INT_IMAGE_3D: return "uimage3D";
237 case GL_UNSIGNED_INT_IMAGE_2D_RECT: return "uimage2DRect";
238 case GL_UNSIGNED_INT_IMAGE_CUBE: return "uimageCube";
239 case GL_UNSIGNED_INT_IMAGE_BUFFER: return "uimageBuffer";
240 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return "uimage1DArray";
241 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return "uimage2DArray";
242 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return "uimage2DMS";
243 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "uimage2DMSArray";
244 case GL_UNSIGNED_INT_ATOMIC_COUNTER: return "atomic_uint";
245 default: break;
246 }
247 return "other data type";
248}
249
250inline const char* CSCI441_INTERNAL::ShaderUtils::GL_shader_type_to_string(
251 const GLenum type
252) {
253 switch(type) {
254 case GL_VERTEX_SHADER: return "Vertex Shader";
255 case GL_TESS_CONTROL_SHADER: return "Tess Ctrl Shader";
256 case GL_TESS_EVALUATION_SHADER: return "Tess Eval Shader";
257 case GL_GEOMETRY_SHADER: return "Geometry Shader";
258 case GL_FRAGMENT_SHADER: return "Fragment Shader";
259 case GL_COMPUTE_SHADER: return "Compute Shader";
260 default: break;
261 }
262 return "other shader type";
263}
264
265inline const char* CSCI441_INTERNAL::ShaderUtils::GL_primitive_type_to_string(
266 const GLenum type
267) {
268 switch(type) {
269 case GL_POINTS: return "Points";
270 case GL_LINES: return "Lines";
271 case GL_LINE_STRIP: return "Line Strip";
272 case GL_LINE_LOOP: return "Line Loop";
273 case GL_LINES_ADJACENCY: return "Line Adjacency";
274 case GL_TRIANGLES: return "Triangles";
275 case GL_TRIANGLE_STRIP: return "Triangle Strip";
276 case GL_TRIANGLES_ADJACENCY: return "Triangle Adjacency";
277 case GL_PATCHES: return "Patches";
278 default: break;
279 }
280 return "other primitive type";
281}
282
283inline void CSCI441_INTERNAL::ShaderUtils::printShaderLog(
284 const GLuint shaderHandle
285) {
286 // check if the handle is to a vertex/fragment shader
287 if( glIsShader( shaderHandle ) ) {
288 GLint maxLength = 0, status = 0, infoLogLength = 0;
289 glGetShaderiv( shaderHandle, GL_INFO_LOG_LENGTH, &maxLength );
290
291 // create a buffer of designated length
292 const auto infoLog = new GLchar[maxLength];
293
294 glGetShaderiv( shaderHandle, GL_COMPILE_STATUS, &status );
295 if( sDEBUG ) printf( "[INFO]: | Shader Handle %2d: Compile%-26s |\n", shaderHandle, (status == 1 ? "d Successfully" : "r Error") );
296
297 // get the info log for the vertex/tesselation/geometry/fragment/compute shader
298 glGetShaderInfoLog(shaderHandle, maxLength, &infoLogLength, infoLog );
299
300 if(infoLogLength > 0 ) {
301 // print info to terminal
302 if( sDEBUG ) printf( "[INFO]: | Shader Handle %d: %s\n", shaderHandle, infoLog );
303 }
304
305 delete[] infoLog;
306 } else {
307 if( sDEBUG ) fprintf( stderr, "[WARN]: | Handle %-3d is not for a Shader |\n", shaderHandle );
308 }
309}
310
311inline void CSCI441_INTERNAL::ShaderUtils::printProgramLog(
312 const GLuint programHandle
313) {
314 // check if the handle is to a vertex/fragment shader
315 if( glIsProgram( programHandle ) ) {
316 GLint maxLength = 0, status = 0, infoLogLength = 0;
317 glGetProgramiv( programHandle, GL_INFO_LOG_LENGTH, &maxLength );
318
319 // create a buffer of designated length
320 const auto infoLog = new GLchar[maxLength];
321
322 glGetProgramiv( programHandle, GL_LINK_STATUS, &status );
323 if( sDEBUG ) printf("[INFO]: | Program Handle %2d: Linke%-28s |\n", programHandle, (status == 1 ? "d Successfully" : "r Error") );
324
325 // get the info log for the vertex/tesselation/geometry/fragment/compute shader
326 glGetProgramInfoLog(programHandle, maxLength, &infoLogLength, infoLog );
327
328 if(infoLogLength > 0 ) {
329 // print info to terminal
330 if( sDEBUG ) printf( "[INFO]: | Program Handle %d: %s\n", programHandle, infoLog );
331 }
332
333 delete[] infoLog;
334 } else {
335 if( sDEBUG ) fprintf( stderr, "[WARN]: | Handle %-3d is not for a Shader Program |\n", programHandle );
336 }
337}
338
339inline void CSCI441_INTERNAL::ShaderUtils::printProgramPipelineLog(
340 const GLuint pipelineHandle
341) {
342 // check if the handle is to a shader program pipeline
343 if( glIsProgramPipeline( pipelineHandle ) ) {
344 GLint maxLength = 0, infoLogLength = 0;
345
346 glGetProgramPipelineiv( pipelineHandle, GL_INFO_LOG_LENGTH, &maxLength );
347
348 // create a buffer of designated length
349 const auto infoLog = new GLchar[maxLength];
350
351 // get the info log for the shader program pipeline
352 glGetProgramPipelineInfoLog(pipelineHandle, maxLength, &infoLogLength, infoLog );
353
354 if( infoLogLength > 0 ) {
355 // print info to terminal
356 if( sDEBUG ) printf( "[INFO]: | Pipeline Handle %d: %s\n", pipelineHandle, infoLog );
357 }
358
359 delete[] infoLog;
360 } else {
361 if( sDEBUG ) fprintf( stderr, "[WARN]: | Handle %-3d is not for a Shader Program Pipeline |\n", pipelineHandle );
362 }
363}
364
365inline GLboolean CSCI441_INTERNAL::ShaderUtils::printSubroutineInfo(
366 const GLuint programHandle,
367 const GLenum shaderStage,
368 const GLboolean printHeader
369) {
370 GLint numSubroutineUniforms = 0;
371 glGetProgramStageiv(programHandle, shaderStage, GL_ACTIVE_SUBROUTINE_UNIFORMS, &numSubroutineUniforms);
372 bool headerPrinted = false;
373 if( numSubroutineUniforms > 0 ) {
374 if( printHeader ) {
375 printf( "[INFO]: >--------------------------------------------------------<\n");
376 headerPrinted = true;
377 }
378 printf("[INFO]: | GL_ACTIVE_SUBROUTINE_UNIFORMS (%-15s): %5i |\n", CSCI441_INTERNAL::ShaderUtils::GL_shader_type_to_string(shaderStage), numSubroutineUniforms);
379 for(int i = 0; i < numSubroutineUniforms; i++ ) {
380 GLchar subroutineName[256];
381 GLint max_length = 256, actual_length = 0;
382 GLint numCompatibleSubroutines = 0;
383
384 glGetActiveSubroutineUniformName(programHandle, shaderStage, i, max_length, &actual_length, subroutineName );
385 glGetActiveSubroutineUniformiv(programHandle, shaderStage, i, GL_NUM_COMPATIBLE_SUBROUTINES, &numCompatibleSubroutines );
386
387 const auto compatibleSubroutines = new GLint[numCompatibleSubroutines];
388 glGetActiveSubroutineUniformiv(programHandle, shaderStage, i, GL_COMPATIBLE_SUBROUTINES, compatibleSubroutines );
389
390 GLint loc = glGetSubroutineUniformLocation(programHandle, shaderStage, subroutineName );
391
392 printf("[INFO]: | %i) name: %-15s #subRoutines: %-5i loc: %2i |\n", i, subroutineName, numCompatibleSubroutines, loc );
393
394 for(int j = 0; j < numCompatibleSubroutines; j++ ) {
395 GLint idx = compatibleSubroutines[j];
396
397 GLchar subroutineImplName[64];
398 GLint max_length2 = 64, actual_length2 = 0;
399 glGetActiveSubroutineName(programHandle, shaderStage, idx, max_length2, &actual_length2, subroutineImplName );
400
401 printf("[INFO]: | %i) subroutine: %-25s index: %2i |\n", j, subroutineImplName, idx );
402 }
403
404 delete[] compatibleSubroutines;
405 }
406 }
407 return !headerPrinted;
408}
409
410inline void CSCI441_INTERNAL::ShaderUtils::printShaderProgramInfo(
411 const GLuint programHandle,
412 const GLboolean hasVertexShader,
413 const GLboolean hasTessControlShader,
414 const GLboolean hasTessEvalShader,
415 const GLboolean hasGeometryShader,
416 const GLboolean hasFragmentShader,
417 const GLboolean hasComputeShader,
418 const GLboolean useLastNewLine = true
419) {
420 GLint major = 0, minor = 0;
421 glGetIntegerv(GL_MAJOR_VERSION, &major);
422 glGetIntegerv(GL_MINOR_VERSION, &minor);
423
424 GLuint shaders[6] = {0};
425 GLint max_count = 6;
426 GLint actual_count = 0;
427
428 GLint max_attr_name_size = 0;
429 GLint max_uniform_name_size = 0;
430
431 // get max var name from program
432 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetActiveAttrib.xhtml
433 glGetProgramiv(programHandle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_size);
434 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_size);
435
436 glGetAttachedShaders(programHandle, max_count, &actual_count, shaders );
437 if(actual_count > 0) {
438 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n");
439 if( sDEBUG ) printf("[INFO]: | GL_ATTACHED_SHADERS: %33i |\n", actual_count);
440 for(int i = 0; i < actual_count; i++ ) {
441 GLint shaderType;
442 glGetShaderiv( shaders[i], GL_SHADER_TYPE, &shaderType );
443 if( sDEBUG ) printf("[INFO]: | %i) %-38s Handle: %2i |\n", i, GL_shader_type_to_string(shaderType), shaders[i]);
444 }
445 }
446
447 if(sDEBUG) {
448 if(hasGeometryShader) {
449 if( major > 3 || (major >= 3 && minor >= 2) ) {
450 GLint verticesOut = 0, inputType = 0, outputType = 0;
451 glGetProgramiv(programHandle, GL_GEOMETRY_VERTICES_OUT, &verticesOut);
452 glGetProgramiv(programHandle, GL_GEOMETRY_INPUT_TYPE, &inputType);
453 glGetProgramiv(programHandle, GL_GEOMETRY_OUTPUT_TYPE, &outputType);
454
455 printf( "[INFO]: >--------------------------------------------------------<\n");
456 printf( "[INFO]: | GEOMETRY SHADER PRIMITIVE I/O |\n");
457 printf( "[INFO]: | Input Type: %40s |\n", GL_primitive_type_to_string(inputType) );
458 printf( "[INFO]: | Output Type: %39s |\n", GL_primitive_type_to_string(outputType) );
459 printf( "[INFO]: | Max Vertices Out: %34d |\n", verticesOut );
460 }
461 }
462 }
463
464 if(hasVertexShader) {
465 GLint numActiveAttributes = 0;
466 glGetProgramiv(programHandle, GL_ACTIVE_ATTRIBUTES, &numActiveAttributes );
467 if( numActiveAttributes > 0 ) {
468 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n");
469 if( sDEBUG ) printf( "[INFO]: | GL_ACTIVE_ATTRIBUTES: %32i |\n", numActiveAttributes );
470 for( int i = 0; i < numActiveAttributes; i++ ) {
471 const auto name = new GLchar[max_attr_name_size];
472 GLint actual_length = 0, size = 0;
473 GLenum type = GL_NONE;
474 glGetActiveAttrib(programHandle, i, max_attr_name_size, &actual_length, &size, &type, name );
475 if( size > 1 ) {
476 for( int j = 0; j < size; j++ ) {
477 // length of string + max array value size (technically it depends on the size of GL type, but I'm not aware a way to get the size)
478 // + array accessors + null
479 int max_array_size = actual_length + 4 + 2 + 1;
480 const auto array_name = new GLchar[max_array_size];
481
482 snprintf( array_name, max_array_size, "%s[%i]", name, j );
483 GLint location = glGetAttribLocation(programHandle, array_name);
484 if( sDEBUG ) printf( "[INFO]: | %i) type: %-15s name: %-13s loc: %2i |\n", i, GLSL_type_to_string( type ), array_name, location );
485 delete[] array_name;
486 }
487 } else {
488 GLint location = glGetAttribLocation(programHandle, name );
489 if( sDEBUG ) printf( "[INFO]: | %i) type: %-15s name: %-13s loc: %2i |\n",i, GLSL_type_to_string( type ), name, location );
490 }
491
492 delete[] name;
493 }
494 }
495 }
496
497 GLint numActiveUniforms = 0;
498 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
499 if( numActiveUniforms > 0 ) {
500 constexpr int NUM_PROPS = 6;
501 GLenum props[NUM_PROPS] = {GL_REFERENCED_BY_VERTEX_SHADER,
502 GL_REFERENCED_BY_TESS_CONTROL_SHADER,
503 GL_REFERENCED_BY_TESS_EVALUATION_SHADER,
504 GL_REFERENCED_BY_GEOMETRY_SHADER,
505 GL_REFERENCED_BY_FRAGMENT_SHADER,
506 GL_NONE};
507
508 if((major == 4 && minor >= 3) || major > 4) {
509 props[5] = GL_REFERENCED_BY_COMPUTE_SHADER;
510 }
511 GLint results[NUM_PROPS] = {0};
512
513 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n" );
514 if( sDEBUG ) printf("[INFO]: | GL_ACTIVE_UNIFORMS: %34i |\n", numActiveUniforms);
515 for(int uIdx = 0; uIdx < numActiveUniforms; uIdx++) {
516 const auto name = new GLchar[max_uniform_name_size];
517 GLint actual_length = 0, size = 0, location = -1;
518 GLenum type = GL_NONE;
519 glGetActiveUniform(programHandle, uIdx, max_uniform_name_size, &actual_length, &size, &type, name );
520 if(size > 1) {
521 for(int j = 0; j < size; j++) {
522 int max_array_size = actual_length + 4 + 2 + 1;
523 const auto array_name = new GLchar[max_array_size];
524 snprintf(array_name, max_array_size, "%s[%i]", name, j);
525 location = glGetUniformLocation(programHandle, array_name);
526 if(location != -1) {
527 if (sDEBUG) printf("[INFO]: | %2i) type: %-15s name: %-13s loc: %2i |\n", uIdx, GLSL_type_to_string(type), array_name, location);
528 }
529 delete[] array_name;
530 }
531 } else {
532 location = glGetUniformLocation(programHandle, name);
533 if(location != -1) {
534 if (sDEBUG) printf("[INFO]: | %2i) type: %-15s name: %-13s loc: %2i |\n", uIdx, GLSL_type_to_string(type), name, location);
535 }
536 }
537
538 if(((major == 4 && minor >= 3) || major > 4) && location != -1) {
539 glGetProgramResourceiv(programHandle, GL_UNIFORM, uIdx, NUM_PROPS, props, NUM_PROPS, nullptr, results);
540 if( sDEBUG ) printf("[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (results[0] ? "Vert" : ""), (results[1] ? "Ctrl" : ""), (results[2] ? "Eval" : ""), (results[3] ? "Geo" : ""), (results[4] ? "Frag" : ""), (results[5] ? "Comp" : ""));
541 }
542
543 delete[] name;
544 }
545 }
546
547 GLint numActiveUniformBlocks = 0;
548 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks);
549 if( numActiveUniformBlocks > 0 ) {
550 int vsCount, tcsCount, tesCount, gsCount, fsCount, csCount;
551 vsCount = tcsCount = tesCount = gsCount = fsCount = csCount = 0;
552
553 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n");
554 if( sDEBUG ) printf("[INFO]: | GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: %20d |\n", numActiveUniformBlocks);
555 for(int i = 0; i < numActiveUniformBlocks; i++ ) {
556 GLint numActiveUniformsInBlock = 0, bindingPoint = 0;
557 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numActiveUniformsInBlock );
558 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_BINDING, &bindingPoint);
559
560 GLint actualLen;
561 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &actualLen);
562 const auto name = new GLchar[actualLen];
563 glGetActiveUniformBlockName(programHandle, i, actualLen, nullptr, name);
564
565 const auto indices = new GLint[numActiveUniformsInBlock];
566 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices);
567
568 const auto offsets = new GLint[numActiveUniformsInBlock];
569 glGetActiveUniformsiv(programHandle, numActiveUniformsInBlock, (GLuint*)indices, GL_UNIFORM_OFFSET, offsets);
570
571 if( sDEBUG ) printf("[INFO]: | %d) %-19s binding: %3d |\n", i, name, bindingPoint);
572
573 GLint vs, tcs, tes, gs, fs, cs;
574 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &vs); if( vs ) vsCount++;
575 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER, &tcs); if( tcs) tcsCount++;
576 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER, &tes); if( tes) tesCount++;
577 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER, &gs); if( gs ) gsCount++;
578 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &fs); if( fs ) fsCount++;
579 if((major == 4 && minor >= 3) || major > 4) {
580 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER, &cs); if( cs ) csCount++;
581 }
582 if( sDEBUG ) printf("[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (vs ? "Vert" : ""), (tcs ? "Ctrl" : ""), (tes ? "Eval" : ""), (gs ? "Geo" : ""), (fs ? "Frag" : ""), (cs ? "Comp" : ""));
583
584 const auto name2 = new char[max_uniform_name_size];
585 for(int j = 0; j < numActiveUniformsInBlock; j++) {
586 GLenum type;
587 int uniSize;
588 glGetActiveUniform(programHandle, indices[j], max_uniform_name_size, &actualLen, &uniSize, &type, name2);
589
590 constexpr GLsizei NUM_ATOMIC_PROPERTIES = 1;
591 GLint atomicIndex[NUM_ATOMIC_PROPERTIES] = {-1};
592 if((major == 4 && minor >= 3) || major > 4) {
593 GLenum atomicProps[NUM_ATOMIC_PROPERTIES] = {GL_ATOMIC_COUNTER_BUFFER_INDEX};
594 glGetProgramResourceiv(programHandle, GL_UNIFORM, indices[j], NUM_ATOMIC_PROPERTIES, atomicProps, NUM_ATOMIC_PROPERTIES, nullptr, atomicIndex);
595 }
596
597 if( atomicIndex[0] == -1 && sDEBUG ) {
598 printf("[INFO]: | %2d) type: %-15s name: %-21s |\n", j, GLSL_type_to_string(type), name2);
599 printf("[INFO]: | uniform index: %3d offset: %4d |\n", indices[j], offsets[j]);
600 }
601 }
602
603 delete[] name;
604 delete[] indices;
605 delete[] offsets;
606 delete[] name2;
607 }
608
609 if( vsCount + tcsCount + tesCount + gsCount + fsCount + csCount > 0 ) {
610 GLint maxUniBlocks = 0;
611 glGetIntegerv( GL_MAX_COMBINED_UNIFORM_BLOCKS, &maxUniBlocks );
612 if( sDEBUG ) printf( "[INFO]: | Shader Uniform Block Counts %2d/%2d |\n", numActiveUniformBlocks, maxUniBlocks);
613 if( hasVertexShader ) {
614 GLint maxVertexUniformBlocks = 0;
615 glGetIntegerv( GL_MAX_VERTEX_UNIFORM_BLOCKS, &maxVertexUniformBlocks );
616
617 if( sDEBUG ) printf( "[INFO]: | Vertex Shader Uniform Blocks: %18d/%2d |\n", vsCount, maxVertexUniformBlocks );
618 }
619 if( hasTessControlShader ) {
620 GLint maxTessControlUniformBlocks = 0;
621 glGetIntegerv( GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, &maxTessControlUniformBlocks );
622
623 if( sDEBUG ) printf( "[INFO]: | Tess Ctrl Shader Uniform Blocks: %15d/%2d |\n", tcsCount, maxTessControlUniformBlocks );
624 }
625 if( hasTessEvalShader ) {
626 GLint maxTessEvalUniformBlocks = 0;
627 glGetIntegerv( GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, &maxTessEvalUniformBlocks );
628
629 if( sDEBUG ) printf( "[INFO]: | Tess Eval Shader Uniform Blocks: %15d/%2d |\n", tesCount, maxTessEvalUniformBlocks );
630 }
631 if( hasGeometryShader ) {
632 GLint maxGeometryUniformBlocks = 0;
633 glGetIntegerv( GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &maxGeometryUniformBlocks );
634
635 if( sDEBUG ) printf( "[INFO]: | Geometry Shader Uniform Blocks: %16d/%2d |\n", gsCount, maxGeometryUniformBlocks );
636 }
637 if( hasFragmentShader ) {
638 GLint maxFragmentUniformBlocks = 0;
639 glGetIntegerv( GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &maxFragmentUniformBlocks );
640
641 if( sDEBUG ) printf( "[INFO]: | Fragment Shader Uniform Blocks: %16d/%2d |\n", fsCount, maxFragmentUniformBlocks );
642 }
643 if( hasComputeShader ) {
644 GLint maxComputeUniformBlocks = 0;
645 glGetIntegerv( GL_MAX_COMPUTE_UNIFORM_BLOCKS, &maxComputeUniformBlocks );
646
647 if( sDEBUG ) printf( "[INFO]: | Compute Shader Uniform Blocks: %17d/%2d |\n", csCount, maxComputeUniformBlocks );
648 }
649 }
650 }
651
652 if( sDEBUG ) {
653 if((major == 4 && minor >= 3) || major > 4) {
654 GLint numSSBO = 0;
655 glGetProgramInterfaceiv(programHandle, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numSSBO);
656 if(numSSBO > 0) {
657 GLint maxLen = 0;
658 glGetProgramInterfaceiv(programHandle, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxLen);
659 const auto ssboName = new GLchar[maxLen];
660 GLsizei ssboNameLen = 0;
661
662 constexpr int NUM_PROPS = 7;
663 GLenum props[NUM_PROPS] = {GL_BUFFER_BINDING,
664 GL_REFERENCED_BY_VERTEX_SHADER,
665 GL_REFERENCED_BY_TESS_CONTROL_SHADER, GL_REFERENCED_BY_TESS_EVALUATION_SHADER,
666 GL_REFERENCED_BY_GEOMETRY_SHADER,
667 GL_REFERENCED_BY_FRAGMENT_SHADER,
668 GL_REFERENCED_BY_COMPUTE_SHADER};
669 GLsizei numWritten = 0;
670 GLint results[NUM_PROPS] = {0};
671
672 int vSSB, teSSB, tcSSB, gSSB, fSSB, cSSB;
673 vSSB = teSSB = tcSSB = gSSB = fSSB = cSSB = 0;
674
675 printf( "[INFO]: >--------------------------------------------------------<\n");
676 printf( "[INFO]: | GL_SHADER_STORAGE_BLOCK: %29d |\n", numSSBO );
677 for(int i = 0; i < numSSBO; i++) {
678 glGetProgramResourceName(programHandle, GL_SHADER_STORAGE_BLOCK, i, maxLen, &ssboNameLen, ssboName);
679 GLuint ssboIndex = glGetProgramResourceIndex(programHandle, GL_SHADER_STORAGE_BLOCK, ssboName);
680 glGetProgramResourceiv(programHandle, GL_SHADER_STORAGE_BLOCK, i, NUM_PROPS, props, NUM_PROPS, &numWritten, results);
681
682 printf( "[INFO]: | %3d) name: %-19s index: %3d binding: %3d |\n", i, ssboName, ssboIndex, results[0] );
683 printf( "[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (results[1] ? "Vert" : ""), (results[2] ? "Ctrl" : ""), (results[3] ? "Eval" : ""), (results[4] ? "Geo" : ""), (results[5] ? "Frag" : ""), (results[6] ? "Comp" : ""));
684
685 if(results[1]) vSSB++;
686 if(results[2]) teSSB++;
687 if(results[3]) tcSSB++;
688 if(results[4]) gSSB++;
689 if(results[5]) fSSB++;
690 if(results[6]) cSSB++;
691 }
692
693 GLint maxSSBCounters = 0;
694 glGetIntegerv( GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxSSBCounters );
695 printf( "[INFO]: | Shader Storage Block Counts: %2d/%2d |\n", numSSBO, maxSSBCounters );
696 if(hasVertexShader) {
697 GLint maxVertSSB = 0;
698 glGetIntegerv( GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertSSB );
699 printf( "[INFO]: | Vertex Shader Storage Blocks: %2d/%2d |\n", vSSB, maxVertSSB );
700 }
701 if(hasTessControlShader) {
702 GLint maxTESSB = 0;
703 glGetIntegerv( GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &maxTESSB );
704 printf( "[INFO]: | Tess Ctrl Shader Storage Blocks: %2d/%2d |\n", teSSB, maxTESSB );
705 }
706 if(hasTessEvalShader) {
707 GLint maxTCSSB = 0;
708 glGetIntegerv( GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, &maxTCSSB );
709 printf( "[INFO]: | Tess Eval Shader Storage Blocks: %2d/%2d |\n", tcSSB, maxTCSSB );
710 }
711 if(hasGeometryShader) {
712 GLint maxGeoSSB = 0;
713 glGetIntegerv( GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, &maxGeoSSB );
714 printf( "[INFO]: | Geometry Shader Storage Blocks: %2d/%2d |\n", gSSB, maxGeoSSB );
715 }
716 if(hasFragmentShader) {
717 GLint maxFragSSB = 0;
718 glGetIntegerv( GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragSSB );
719 printf( "[INFO]: | Fragment Shader Storage Blocks: %2d/%2d |\n", fSSB, maxFragSSB );
720 }
721 if(hasComputeShader) {
722 GLint maxComputeSSB = 0;
723 glGetIntegerv( GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeSSB );
724 printf( "[INFO]: | Compute Shader Storage Blocks: %2d/%2d |\n", cSSB, maxComputeSSB );
725 }
726
727 delete[] ssboName;
728 }
729 }
730
731 if((major == 4 && minor >= 2) || major > 4) {
732 GLint numAtomicCounters = 0;
733 glGetProgramInterfaceiv(programHandle, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numAtomicCounters);
734
735 if(numAtomicCounters > 0) {
736 constexpr int NUM_PROPS = 6;
737 GLenum props[NUM_PROPS] = {GL_REFERENCED_BY_VERTEX_SHADER,
738 GL_REFERENCED_BY_TESS_CONTROL_SHADER,
739 GL_REFERENCED_BY_TESS_EVALUATION_SHADER,
740 GL_REFERENCED_BY_GEOMETRY_SHADER,
741 GL_REFERENCED_BY_FRAGMENT_SHADER,
742 GL_NONE};
743
744 if((major == 4 && minor >= 3) || major > 4) {
745 props[5] = GL_REFERENCED_BY_COMPUTE_SHADER;
746 }
747
748 GLsizei numWritten = 0;
749 GLint results[NUM_PROPS] = {0};
750
751 printf( "[INFO]: >--------------------------------------------------------<\n");
752 printf("[INFO]: | GL_ATOMIC_COUNTER_BUFFER: %28d |\n", numAtomicCounters );
753
754 int vAC, teAC, tcAC, gAC, fAC, cAC;
755 vAC = teAC = tcAC = gAC = fAC = cAC = 0;
756
757 for(GLint acIdx = 0; acIdx < numAtomicCounters; acIdx++) {
758 GLint binding = -1, bufferSize = 0, nac = 0;
759
760 glGetActiveAtomicCounterBufferiv(programHandle, acIdx, GL_ATOMIC_COUNTER_BUFFER_BINDING, &binding);
761 glGetActiveAtomicCounterBufferiv(programHandle, acIdx, GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE, &bufferSize);
762 glGetActiveAtomicCounterBufferiv(programHandle, acIdx, GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS, &nac);
763
764 const auto uniformIndices = new GLint[nac];
765 const auto atomicOffsets = new GLint[nac];
766 const auto atomicName = new GLchar[max_uniform_name_size];
767
768 glGetActiveAtomicCounterBufferiv(programHandle, acIdx, GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES, uniformIndices);
769 glGetActiveUniformsiv(programHandle, nac, (GLuint*)uniformIndices, GL_UNIFORM_OFFSET, atomicOffsets);
770 glGetProgramResourceiv(programHandle, GL_ATOMIC_COUNTER_BUFFER, acIdx, NUM_PROPS, props, NUM_PROPS, &numWritten, results);
771
772 // increment counts of which shaders have an atomic counter
773 if(results[0]) vAC++;
774 if(results[1]) teAC++;
775 if(results[2]) tcAC++;
776 if(results[3]) gAC++;
777 if(results[4]) fAC++;
778 if(results[5]) cAC++;
779
780 printf( "[INFO]: | %d) binding: %11d buffer size: %4d |\n", acIdx, binding, bufferSize );
781 printf( "[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (results[0] ? "Vert" : ""), (results[1] ? "Ctrl" : ""), (results[2] ? "Eval" : ""), (results[3] ? "Geo" : ""), (results[4] ? "Frag" : ""), (results[5] ? "Comp" : ""));
782
783 GLint acCtr = 0, actualLen = 0, uniSize = 0;
784 GLenum type = GL_NONE;
785 for(GLint uniIdx = 0; uniIdx < nac; uniIdx++) {
786 glGetActiveUniform(programHandle, uniformIndices[uniIdx], max_uniform_name_size, &actualLen, &uniSize, &type, atomicName);
787
788 constexpr GLsizei NUM_ATOMIC_PROPERTIES = 1;
789 GLenum atomicProps[NUM_ATOMIC_PROPERTIES] = {GL_ATOMIC_COUNTER_BUFFER_INDEX};
790 GLint atomicIndex [NUM_ATOMIC_PROPERTIES] = {-1};
791 glGetProgramResourceiv(programHandle, GL_UNIFORM, uniformIndices[uniIdx], NUM_ATOMIC_PROPERTIES, atomicProps, NUM_ATOMIC_PROPERTIES, nullptr, atomicIndex);
792
793 if(atomicIndex[0] == acIdx) {
794 printf( "[INFO]: | %3d) type: %-15s name: %-21s |\n", acCtr++, GLSL_type_to_string(type), atomicName );
795 printf( "[INFO]: | uniform index: %3d offset: %7d |\n", uniformIndices[uniIdx], atomicOffsets[uniIdx] );
796 }
797 }
798
799 delete[] uniformIndices;
800 delete[] atomicOffsets;
801 delete[] atomicName;
802 }
803
804 GLint maxAtomicCounters = 0;
805 glGetIntegerv( GL_MAX_COMBINED_ATOMIC_COUNTERS, &maxAtomicCounters );
806 printf("[INFO]: | Atomic Counter Counts: %4d/%4d |\n", numAtomicCounters, maxAtomicCounters );
807 if(hasVertexShader) {
808 GLint maxVertAtomicCounters = 0;
809 glGetIntegerv( GL_MAX_VERTEX_ATOMIC_COUNTERS, &maxVertAtomicCounters );
810 printf( "[INFO]: | Vertex Atomic Counters: %4d/%4d |\n", vAC, maxVertAtomicCounters );
811 }
812 if(hasTessControlShader) {
813 GLint maxTCAtomicCounters = 0;
814 glGetIntegerv( GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, &maxTCAtomicCounters );
815 printf( "[INFO]: | Tess Ctrl Atomic Counters: %4d/%4d |\n", teAC, maxTCAtomicCounters );
816 }
817 if(hasTessEvalShader) {
818 GLint maxTEAtomicCounters = 0;
819 glGetIntegerv( GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &maxTEAtomicCounters );
820 printf( "[INFO]: | Tess Eval Atomic Counters: %4d/%4d |\n", tcAC, maxTEAtomicCounters );
821 }
822 if(hasGeometryShader) {
823 GLint maxGeoAtomicCounters = 0;
824 glGetIntegerv( GL_MAX_GEOMETRY_ATOMIC_COUNTERS, &maxGeoAtomicCounters );
825 printf( "[INFO]: | Geometry Atomic Counters: %4d/%4d |\n", gAC, maxGeoAtomicCounters );
826 }
827 if(hasFragmentShader) {
828 GLint maxFragAtomicCounters = 0;
829 glGetIntegerv( GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &maxFragAtomicCounters );
830 printf( "[INFO]: | Fragment Atomic Counters: %4d/%4d |\n", fAC, maxFragAtomicCounters );
831 }
832 if(hasComputeShader) {
833 GLint maxComputeAtomicCounters = 0;
834 glGetIntegerv( GL_MAX_COMPUTE_ATOMIC_COUNTERS, &maxComputeAtomicCounters );
835 printf( "[INFO]: | Compute Atomic Counters: %4d/%4d |\n", cAC, maxComputeAtomicCounters );
836 }
837 }
838 }
839
840 if( major >= 4 ) {
841 GLboolean printHeader = GL_TRUE;
842 if( hasVertexShader ) printHeader = printSubroutineInfo(programHandle, GL_VERTEX_SHADER, printHeader );
843 if( hasTessControlShader) printHeader = printSubroutineInfo(programHandle, GL_TESS_CONTROL_SHADER, printHeader );
844 if( hasTessEvalShader) printHeader = printSubroutineInfo(programHandle, GL_TESS_EVALUATION_SHADER, printHeader );
845 if( hasGeometryShader ) printHeader = printSubroutineInfo(programHandle, GL_GEOMETRY_SHADER, printHeader );
846 if( hasFragmentShader ) printHeader = printSubroutineInfo(programHandle, GL_FRAGMENT_SHADER, printHeader );
847 if( hasComputeShader ) printSubroutineInfo(programHandle, GL_COMPUTE_SHADER, printHeader );
848 }
849 }
850
851 if(useLastNewLine && sDEBUG) printf( "[INFO]: \\--------------------------------------------------------/\n\n");
852}
853
854inline GLuint CSCI441_INTERNAL::ShaderUtils::compileShader(
855 const char *filename,
856 const GLenum shaderType
857) {
858 // will hold contents of shader source code, loaded from file
859 GLchar *shaderString;
860
861 // read in each text file and store the contents in a string
862 if( readTextFromFile( filename, shaderString ) ) {
863 // generate a shader handle for the corresponding shader type
864 GLuint shaderHandle = glCreateShader( shaderType );
865
866 // send the contents of each program to the GPU
867 glShaderSource( shaderHandle, 1, (const char**)&shaderString, nullptr );
868
869 // we are good programmers so free up the memory used by each buffer
870 delete [] shaderString;
871
872 // compile each shader on the GPU
873 glCompileShader( shaderHandle );
874
875 // check the shader log
876 printShaderLog( shaderHandle );
877
878 // return the handle of our shader
879 return shaderHandle;
880 } else {
881 return 0;
882 }
883}
884
885#endif // CSCI441_SHADER_UTILS_HPP