1 module d2d.rendering.shader;
2 
3 import d2d;
4 
5 import std.conv : to;
6 
7 /// All valid types of shaders for the `Shader` class.
8 enum ShaderType : ubyte
9 {
10 	/// Vertex Shader
11 	Vertex,
12 	/// Tessellation Control Shader
13 	TessControl,
14 	/// Tessellation Evaluation Shader
15 	TessEvaluation,
16 	/// Geometry Shader
17 	Geometry,
18 	/// Fragment/Pixel Shader
19 	Fragment
20 }
21 
22 /// Class containing a single shader for combining in a ShaderProgram.
23 class Shader : IVerifiable
24 {
25 	/// Loads the shader content into memory.
26 	public bool load(ShaderType type, string content)
27 	{
28 		this.content = content;
29 		switch (type)
30 		{
31 		case ShaderType.Vertex:
32 			_id = glCreateShader(GL_VERTEX_SHADER);
33 			break;
34 		case ShaderType.TessControl:
35 			if (!hasARBTesselationShader)
36 				throw new Exception(
37 						"Tried to create a TESS_CONTROL_SHADER without GL_ARB_tessellation_shader extension being available");
38 
39 			_id = glCreateShader(GL_TESS_CONTROL_SHADER);
40 			break;
41 		case ShaderType.TessEvaluation:
42 			if (!hasARBTesselationShader)
43 				throw new Exception(
44 						"Tried to create a TESS_EVALUATION_SHADER without GL_ARB_tessellation_shader extension being available");
45 
46 			_id = glCreateShader(GL_TESS_EVALUATION_SHADER);
47 			break;
48 		case ShaderType.Geometry:
49 			_id = glCreateShader(GL_GEOMETRY_SHADER);
50 			break;
51 		case ShaderType.Fragment:
52 			_id = glCreateShader(GL_FRAGMENT_SHADER);
53 			break;
54 		default:
55 			throw new Exception("ShaderType " ~ type.to!string ~ " is not defined!");
56 		}
57 
58 		const int len = cast(const(int)) content.length;
59 
60 		glShaderSource(_id, 1, [content.ptr].ptr, &len);
61 		return true;
62 	}
63 
64 	/// Creates a shader, loads the content and compiles it in one function.
65 	static Shader create(ShaderType type, string content)
66 	{
67 		Shader shader = new Shader();
68 		shader.load(type, content);
69 		shader.compile();
70 		return shader;
71 	}
72 
73 	/// Compiles the shader and throws an Exception if an error occured.
74 	/// Will automatically be called when attaching the shader to a ShaderProgram instance.
75 	public bool compile()
76 	{
77 		if (compiled)
78 			return true;
79 		glCompileShader(_id);
80 		int success = 0;
81 		glGetShaderiv(_id, GL_COMPILE_STATUS, &success);
82 
83 		if (success == 0)
84 		{
85 			int logSize = 0;
86 			glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logSize);
87 
88 			char* log = new char[logSize].ptr;
89 			glGetShaderInfoLog(_id, logSize, &logSize, &log[0]);
90 
91 			throw new Exception(cast(string) log[0 .. logSize]);
92 		}
93 		compiled = true;
94 		return true;
95 	}
96 
97 	/// The OpenGL id of this shader.
98 	public @property uint id()
99 	{
100 		return _id;
101 	}
102 
103 	/// Checks if this shader is valid.
104 	public @property bool valid()
105 	{
106 		return _id > 0;
107 	}
108 
109 	private uint _id = 0;
110 	private string content;
111 	private bool compiled = false;
112 }