1 /**
2 Copyright: Copyright (c) 2013-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module voxelman.graphics.shaderprogram;
8 
9 import std.exception;
10 import std.stdio;
11 import std.string;
12 import std.variant;
13 import voxelman.graphics.gl;
14 
15 final class ShaderProgram
16 {
17 	bool isInited;
18 	GLuint handle = 0;
19 	string errorLog;
20 
21 	this(in string vertShaderSource, in string fragShaderSource)
22 	{
23 		handle = checkgl!glCreateProgram();
24 		attachShader(GL_VERTEX_SHADER, vertShaderSource);
25 		attachShader(GL_FRAGMENT_SHADER, fragShaderSource);
26 		isInited = true;
27 	}
28 
29 	void close()
30 	{
31 		if (isInited) {
32 			checkgl!glDeleteProgram(handle);
33 			isInited = false;
34 		}
35 	}
36 
37 	void bind()
38 	{
39 		checkgl!glUseProgram(handle);
40 	}
41 
42 	static void unbind()
43 	{
44 		checkgl!glUseProgram(0);
45 	}
46 
47 	void attachShader(in GLenum shaderType, in string shaderSource)
48 	{
49 		GLuint shader = checkgl!glCreateShader(shaderType);
50 
51 		const char* fileData = toStringz(shaderSource);
52 		checkgl!glShaderSource(shader, 1, &fileData, null);
53 		checkgl!glCompileShader(shader);
54 
55 		int status;
56 		checkgl!glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
57 		if (status == GL_FALSE)
58 		{
59 			int length;
60 			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
61 
62 			char[] error = new char[length];
63 			checkgl!glGetShaderInfoLog(shader, length, null, cast(char*)error);
64 
65 			string shaderTypeString;
66 			switch(shaderType)
67 			{
68 				case GL_VERTEX_SHADER:   shaderTypeString = "vertex"; break;
69 				//case GL_GEOMETRY_SHADER: shaderTypeString = "geometry"; break; // not supported in OpenGL 3.1
70 				case GL_FRAGMENT_SHADER: shaderTypeString = "fragment"; break;
71 				default: break;
72 			}
73 
74 			errorLog ~= "Compile failure in " ~ shaderTypeString ~ " shader:\n" ~ error~"\n";
75 		}
76 		checkgl!glAttachShader(handle, shader);
77 	}
78 
79 	// if ( !myShaderProgram.compile() )
80 	//     writeln( myShaderProgram.errorLog );
81 	bool compile()
82 	{
83 		checkgl!glLinkProgram(handle);
84 
85 		GLint linkStatus;
86 		checkgl!glGetProgramiv(handle, GL_LINK_STATUS, &linkStatus);
87 
88 		scope(exit) // Detach all shaders after compilation
89 		{
90 			GLuint[3] shaders;
91 			GLsizei count;
92 
93 			checkgl!glGetAttachedShaders(handle, cast(int)shaders.length, &count, cast(uint*)shaders);
94 
95 			for( uint i=0; i<count; ++i )
96 			{
97 				checkgl!glDetachShader(handle, shaders[i]);
98 				checkgl!glDeleteShader(shaders[i]);
99 			}
100 		}
101 
102 		if ( linkStatus == GL_FALSE )
103 		{
104 			GLint infoLogLength;
105 			checkgl!glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &infoLogLength);
106 
107 			char[] strInfoLog = new char[infoLogLength];
108 			checkgl!glGetProgramInfoLog(handle, infoLogLength, null, cast(char*)strInfoLog);
109 			errorLog ~= "Linker failure: " ~ strInfoLog ~ "\n";
110 
111 			return false;
112 		}
113 		return true;
114 	}
115 }