1 /**
2  * このモジュールをユーザーが直接使用することはありません。
3  */
4 
5 module grape.shader;
6 
7 import derelict.opengl3.gl3;
8 
9 import std.exception : enforce;
10 import std.stdio;
11 import std.traits : EnumMembers;
12 
13 enum ShaderType {
14   Vertex = GL_VERTEX_SHADER,
15   Fragment = GL_FRAGMENT_SHADER 
16 }
17 
18 enum ShaderProgramType {
19   ClassicNormal = 0,
20   ClassicTexture = 1,
21   Font = 2,
22   Normal = 3,
23   Texture = 4,
24   Diffuse = 5,
25   ADS = 6,
26   GaussianX = 7,
27   GaussianY = 8,
28 }
29 
30 mixin template ClassicNormalShaderSource() {
31   void delegate(out string, out string) ClassicNormalShader = (out string vShader, out string fShader) {
32     vShader = q{
33       attribute vec3 pos;
34       attribute vec4 color;
35       varying vec4 vColor;
36 
37       void main() {
38         vColor = color;
39         gl_Position = vec4(pos, 1.0);
40       }
41     };
42 
43     fShader = q{
44       varying vec4 vColor;
45 
46       void main() {
47         gl_FragColor = vColor;
48       }
49     };
50   };
51 }
52 
53 mixin template ClassicTextureShaderSource() {
54   void delegate(out string, out string) ClassicTextureShader = (out string vShader, out string fShader) {
55     vShader = q{
56       attribute vec3 pos;
57       attribute vec4 color;
58       attribute vec2 texCoord;
59       varying vec4 vColor;
60       varying vec2 vTexCoord;
61 
62       void main() {
63         vColor = color;
64         vTexCoord = texCoord;
65         gl_Position = vec4(pos, 1.0);
66       }
67     };
68 
69     fShader = q{
70       uniform sampler2D tex;
71       varying vec4 vColor;
72       varying vec2 vTexCoord;
73 
74       void main() {
75         vec4 smpColor = texture2D(tex, vTexCoord);
76         // vec4 smpColor = texture2D(tex, vTexCoord);
77         gl_FragColor = smpColor;
78         //gl_FragColor = vColor * smpColor;
79       }
80     };
81   };
82 }
83 
84 // pvmMatrixの設定をしていないのでデフォルト座標から見ている...はず
85 // eye: (0, 0, 0);
86 // center: (0, 0, -1);
87 // up: (0, 1, 0);
88 mixin template FontShaderSource() {
89   void delegate(out string, out string) FontShader = (out string vShader, out string fShader) {
90     vShader = q{
91       attribute vec3 pos;
92       attribute vec2 texCoord;
93       varying vec2 vTexCoord;
94 
95       void main() {
96         vTexCoord = texCoord;
97         gl_Position = vec4(pos, 1.0);
98       }
99     };
100 
101     fShader = q{
102       uniform sampler2D tex;
103       varying vec2 vTexCoord;
104 
105       void main() {
106         vec4 smpColor = texture2D(tex, vTexCoord);
107         gl_FragColor = smpColor;
108       }
109     };
110   };
111 }
112 
113 mixin template NormalShaderSource() {
114   void delegate(out string, out string) NormalShader = (out string vShader, out string fShader) {
115     vShader = q{
116       attribute vec3 pos;
117       attribute vec4 color;
118       uniform mat4 pvmMatrix;
119       varying vec4 vColor;
120 
121       void main() {
122         vColor = color;
123         gl_Position = pvmMatrix * vec4(pos, 1.0);
124       }
125     };
126 
127     fShader = q{
128       varying vec4 vColor;
129 
130       void main() {
131         gl_FragColor = vColor;
132       }
133     };
134   };
135 }
136 
137 mixin template TextureShaderSource() {
138   void delegate(out string, out string) TextureShader = (out string vShader, out string fShader) {
139     vShader = q{
140       attribute vec3 pos;
141       attribute vec2 texCoord;
142       varying vec2 vTexCoord;
143       uniform mat4 pvmMatrix;
144       //attribute vec4 color;
145       //varying vec4 vColor;
146 
147       void main() {
148         //vColor = color;
149         vTexCoord = texCoord;
150         gl_Position = pvmMatrix * vec4(pos, 1.0); 
151       }
152     };
153 
154     fShader = q{
155       uniform sampler2D tex;
156       varying vec2 vTexCoord;
157       //varying vec4 vColor;
158 
159       void main() {
160         vec4 smpColor = texture2D(tex, vTexCoord);
161         //gl_FragColor = smpColor + vec4(1.0, 1.0, 1.0, 0.0);;
162         gl_FragColor = smpColor;
163         //gl_FragColor = smpColor + vec4(0.2, 0.2, 0.2, 0.0);
164         //gl_FragColor = vec4(0.2, 0.2, 0.2, 0.3);
165         /*
166         if (smpColor.a < 0.5) {
167           discard;
168         } else {
169           gl_FragColor = smpColor;
170         }
171         */
172         //gl_FragColor = vColor;
173         //gl_FragColor = smpColor + vColor;
174         //gl_FragColor = vec4(smpColor.rgb, vColor.a * smpColor.a);
175       }
176     };
177   };
178 }
179 
180 mixin template DiffuseShaderSource() {
181   void delegate(out string, out string) DiffuseShader = (out string vShader, out string fShader) {
182     vShader = q{
183       attribute vec3 pos;
184       attribute vec3 normal;
185       attribute vec4 color;
186 
187       uniform vec3 lightPos;
188 
189       uniform mat4 pvmMatrix;
190       uniform mat4 invMatrix;
191 
192       varying vec4 vColor;
193       
194       void main() {
195         vec3 invLight = normalize(invMatrix * vec4(lightPos, 0.0));
196         float diffuse = clamp(dot(normal, invLight), 0.1, 1.0);
197         vColor = color * vec4(vec3(diffuse), 1.0);
198         gl_Position = pvmMatrix * vec4(pos, 1.0); 
199       }
200     };
201 
202     fShader = q{
203       varying vec4 vColor;
204 
205       void main() {
206         gl_FragColor = vColor;
207       }
208     };
209   };
210 }
211 
212 mixin template ADSShaderSource() {
213   void delegate(out string, out string) ADSShader = (out string vShader, out string fShader) {
214     vShader = q{
215       attribute vec3 pos;
216       attribute vec3 normal;
217       attribute vec4 color;
218 
219       uniform vec3 lightPos;
220       uniform vec3 eyePos;
221       uniform vec4 ambientColor;
222 
223       uniform mat4 pvmMatrix;
224       uniform mat4 invMatrix;
225 
226       varying vec4 vColor;
227       
228       void main() {
229         vec3 invLight = normalize(invMatrix * vec4(lightPos, 0.0));
230         vec3 invEye = normalize(invMatrix * vec4(eyePos, 0.0));
231         vec3 halfLE = normalize(invLight + invEye);
232         float diffuse = clamp(dot(normal, invLight), 0.0, 1.0);
233         float specular = pow(clamp(dot(normal, halfLE), 0.0, 1.0), 50.0);
234         vec4 light = color * vec4(vec3(diffuse), 1.0) + vec4(vec3(specular), 1.0);
235         vColor = light + ambientColor;
236         gl_Position = pvmMatrix * vec4(pos, 1.0); 
237       }
238     };
239 
240     fShader = q{
241       varying vec4 vColor;
242 
243       void main() {
244         gl_FragColor = vColor;
245       }
246     };
247   };
248 }
249 
250 mixin template GaussianShaderSource() {
251   void delegate(out string, out string) GaussianShader = (out string vShader, out string fShader) {
252     vShader = q{
253       attribute vec2 pos;
254       attribute vec2 texCoord;
255       varying vec2 vTexCoord;
256 
257       void main() {
258         gl_Position = vec4(pos, 0.0, 1.0); 
259         vTexCoord = texCoord;
260       }
261     };
262 
263     fShader = q{
264       uniform sampler2D tex;
265       uniform float weight[8];
266       uniform int type;
267       uniform vec2 resolution;
268       varying vec2 vTexCoord;
269 
270       void main() {
271         vec2 t = vec2(1.0) / resolution;
272         vec4 color = texture2D(tex, vTexCoord) * weight[0];
273 
274         if (type == 0) {
275           for (int i=1; i<8; ++i) {
276             color += texture2D(tex, (gl_FragCoord.xy + vec2(-1*i, 0)) * t) * weight[i];
277             color += texture2D(tex, (gl_FragCoord.xy + vec2(1*i, 0)) * t) * weight[i];
278           }
279         } else if (type == 1) {
280           for (int i=1; i<8; ++i) {
281             color += texture2D(tex, (gl_FragCoord.xy + vec2(0, -1*i)) * t) * weight[i];
282             color += texture2D(tex, (gl_FragCoord.xy + vec2(0, 1*i)) * t) * weight[i];
283           }
284         }
285 
286         gl_FragColor = color;
287       }
288     };
289   };
290 }
291 
292 mixin template FilterShaderSource() {
293   void delegate(out string, out string) FilterShader = (out string vShader, out string fShader) {
294     vShader = q{
295       attribute vec3 pos;
296       attribute vec2 texCoord;
297       varying vec2 vTexCoord;
298       //uniform mat4 pvmMatrix;
299 
300       void main() {
301         //gl_Position = pvmMatrix * vec4(pos, 0.0, 1.0); 
302         gl_Position = vec4(pos, 1.0); 
303         vTexCoord = texCoord;
304       }
305     };
306 
307     fShader = q{
308       uniform sampler2D tex;
309       varying vec2 vTexCoord;
310 
311       void main() {
312         vec4 smpColor = texture2D(tex, vTexCoord);
313         gl_FragColor = smpColor;
314         //gl_FragColor = (smpColor.rgb, 0.2);
315         //gl_FragColor = smpColor + vec4(0.2, 0.0, 0.0, 1.0);
316       }
317     };
318   };
319 }
320 
321 class Shader {
322   public:
323     this(in ShaderType type) {
324       generate(type);
325     };
326 
327     this(in ShaderType type, in string shaderCode) {
328       this(type);
329       compile(shaderCode);
330     }
331 
332     ~this() {
333       eliminate();
334     }
335 
336     void compile(in string shaderCode) {
337       auto fst = &shaderCode[0];
338       int len = cast(int)shaderCode.length; // TODO
339       glShaderSource(_shader, 1, &fst, &len);
340       glCompileShader(_shader);
341 
342       GLint result;
343       glGetShaderiv(_shader, GL_COMPILE_STATUS, &result);
344       enforce(result != GL_FALSE, "glCompileShader() faild");
345     }
346 
347     alias _shader this; // TODO
348 
349   private:
350     void generate(in ShaderType type) {
351       _shader = glCreateShader(type);
352       enforce(_shader, "glCreateShader() faild");
353     }
354 
355     void eliminate() {
356       glDeleteShader(_shader); 
357     }
358 
359     GLuint _shader;
360 }
361 
362 class ShaderProgram {
363   public:
364     this() {
365       generate();
366     }
367 
368     this(Shader vs, Shader fs) {
369       this();
370       attach(vs, fs);
371     }
372 
373     ~this() {
374       eliminate();
375     }
376 
377     void attach(T)(in T vs, in T fs) {
378       glAttachShader(_program, vs);
379       glAttachShader(_program, fs);
380       glLinkProgram(_program);
381 
382       int linked;
383       glGetProgramiv(_program, GL_LINK_STATUS, &linked);
384       enforce(linked != GL_FALSE, "glLinkProgram() faild");
385     }
386 
387     void use() {
388       glUseProgram(_program);
389     }
390 
391     alias _program this;
392     GLuint _program;
393 
394   private:
395     void generate() {
396       _program = glCreateProgram();
397       enforce(_program, "glCreateProgram() faild");
398     }
399 
400     void eliminate() {
401       glDeleteProgram(_program);
402     }
403 }
404