1 module Engine.Shader;
2 
3 import std.stdio;
4 import derelict.opengl3.gl;
5 import Engine.Batch;
6 import gl3n.linalg;
7 
8 
9 class Shader
10 {
11 	immutable GLuint Program;
12 	package static GLuint currentProgram = -1;
13 	Attribute[string] attributes;
14 
15 	@property const(Attribute[string]) Attributes() {
16 		return attributes;
17 	}
18 
19 	this(immutable string vertexShaderSource,immutable string fregmentShaderSource)
20 	{
21 		auto vertexShader = glCreateShader(GL_VERTEX_SHADER); 
22 
23 		auto vertexSourcePtr = cast(const char*)vertexShaderSource.ptr;
24 		glShaderSource(vertexShader, 1, &vertexSourcePtr , null);
25 		glCompileShader(vertexShader);
26 
27 		int result = 0;
28 		glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &result);
29 		if (result != GL_TRUE) {
30 			int InfoLogLength = 0;
31 			glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &InfoLogLength);
32 			if ( InfoLogLength > 0 ){
33 				char[] message = new char[InfoLogLength];
34 				scope( exit )  destroy(message); 
35 				glGetShaderInfoLog(vertexShader, InfoLogLength, null, cast( char*)&message[0]);
36 				throw new Exception(cast(string)message);
37 			}
38 		}
39 
40 		auto fregmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
41 
42 		auto fregmentShaderPtr = cast(const char*)fregmentShaderSource.ptr;
43 		glShaderSource(fregmentShader, 1, &fregmentShaderPtr , null);
44 		glCompileShader(fregmentShader);
45 
46 		result = 0;
47 		glGetShaderiv(fregmentShader, GL_COMPILE_STATUS, &result);
48 		if (result != GL_TRUE) {
49 			int InfoLogLength = 0;
50 			glGetShaderiv(fregmentShader, GL_INFO_LOG_LENGTH, &InfoLogLength);
51 			if ( InfoLogLength > 0 ){
52 				char[] message = new char[InfoLogLength];
53 				scope( exit )  destroy(message) ;
54 				glGetShaderInfoLog(fregmentShader, InfoLogLength, null, cast( char*)&message[0]);
55 				throw new Exception(cast(string)message);
56 			}
57 		}
58 
59 		auto program = glCreateProgram();
60 		glAttachShader(program, vertexShader);
61 		glAttachShader(program, fregmentShader);
62 		glLinkProgram(program);
63 
64 		result = 0;
65 		glGetProgramiv(program, GL_LINK_STATUS, &result);
66 		if (result != GL_TRUE) {
67 			int InfoLogLength = 0;
68 			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &InfoLogLength);
69 			if ( InfoLogLength > 0 ){
70 				char[] message = new char[InfoLogLength];
71 				scope( exit )  destroy(message) ; 
72 				glGetProgramInfoLog(program, InfoLogLength, null, cast( char*)&message[0]);
73 				throw new Exception(cast(string)message);
74 			}
75 		}
76 
77 		int attribs = 0;
78 		glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attribs);
79 		int maxAttribLen = 0;
80 		glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLen);
81 
82 
83 		for (int i =0;i<attribs;i++) {
84 			int len = 0;
85 			int attribSize = 0;
86 			GLenum type = 0;
87 			char[] message = new char[maxAttribLen];
88 			glGetActiveAttrib(program,i,maxAttribLen,&len,&attribSize,&type,cast( char*)&message[0]);
89 			message = message[0..len];
90 			auto location = glGetAttribLocation(program, cast( char*)&message[0]);
91 			this.attributes[cast(string)(message)] = new Attribute(i,location,cast(string)(message),type);
92 		}
93 
94 		attribs = 0;
95 		glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &attribs);
96 		maxAttribLen = 0;
97 		glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxAttribLen);
98 
99 		for (int i =0;i<attribs;i++) {
100 			int len = 0;
101 			int attribSize = 0;
102 			GLenum type = 0;
103 			char[] message = new char[maxAttribLen];
104 			glGetActiveUniform(program,i,maxAttribLen,&len,&attribSize,&type,cast( char*)&message[0]);
105 			message = message[0..len];
106 			auto location = glGetUniformLocation(program, cast( char*)&message[0]);
107 			this.attributes[cast(string)(message)] = new Attribute(i,location,cast(string)(message),type);
108 		}
109 
110 
111 
112 
113 		Program = program;
114 	}
115 
116 	public void Use() {
117 		if (Program != currentProgram) {
118 			currentProgram = Program;
119 			glUseProgram(Program);
120 		}
121 	}
122 }
123 
124 
125 
126 class Attribute {
127 	package this(int index, uint location, string name, GLenum type) {
128 		this.index = index;
129 		this.location = location;
130 		this.name = name;
131 		this.type = type;
132 	}
133 
134 	immutable int index;
135 	immutable uint location;
136 	immutable string name;
137 	immutable GLenum type;
138 
139 	final void Set(vec4 v) const {
140 		glUniform4f(location, v.x,v.y,v.z,v.w);
141 	}
142 
143 	final void Set(vec3 v) const {
144 		glUniform3f(location, v.x,v.y,v.z);
145 	}
146 
147 	final void Set(vec2 v) const {
148 		glUniform2f(location, v.x,v.y);
149 	}
150 
151 	final void Set(float v) const {
152 		glUniform1f(location, v);
153 	}
154 
155 	final void Set(vec4d v) const {
156 		glUniform4d(location, v.x,v.y,v.z,v.w);
157 	}
158 
159 	final void Set(vec3d v) const {
160 		glUniform3d(location, v.x,v.y,v.z);
161 	}
162 
163 	final void Set(vec2d v) const {
164 		glUniform2d(location, v.x,v.y);
165 	}
166 
167 	final void Set(double v) const {
168 		glUniform1d(location, v);
169 	}
170 
171 	final void Set(vec4i v) const {
172 		glUniform4i(location, v.x,v.y,v.z,v.w);
173 	}
174 
175 	final void Set(vec3i v) const {
176 		glUniform3i(location, v.x,v.y,v.z);
177 	}
178 
179 	final void Set(vec2i v) const {
180 		glUniform2i(location, v.x,v.y);
181 	}
182 
183 	final void Set(int v) const {
184 		glUniform1i(location, v);
185 	}
186 
187 	final void Set(bool v) const {
188 		glUniform1i(location, cast(bool)v);
189 	}
190 
191 	final void Set(ref mat4 m) const {
192 		glUniformMatrix4fv(location, 1, GL_TRUE, m.value_ptr);
193 	}
194 
195 	final void Set(mat4 m) const {
196 		glUniformMatrix4fv(location, 1, GL_TRUE, m.value_ptr);
197 	}
198 }
199