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