1 
2 module dglsl.shader;
3 
4 import std.string;
5 import std.conv;
6 
7 import derelict.opengl3.gl3;
8 
9 import dglsl.type;
10 import dglsl.sampler;
11 import dglsl.translator;
12 
13 class ShaderBase {
14     mixin TextureLookupFunctions;
15 
16     protected GLuint _shaderid;
17     @property auto id() const { return _shaderid; }
18 }
19 
20 enum input;
21 enum output;
22 enum uniform;
23 enum ignore;
24 
25 private struct MaxVertices {
26     int value = -1;
27 }
28 private struct Location {
29     int value = -1;
30 }
31 private struct Primitive {
32     string value;
33 }
34 struct Layout {
35     Primitive qualifier;
36     MaxVertices maxVertices;
37     Location location;
38 
39     string glsl() {
40         import std.conv;
41         import std.array;
42         string[] lst;
43         if (qualifier != Primitive.init) lst ~= qualifier.value;
44         if (maxVertices != MaxVertices.init) lst ~= "max_vertices = " ~ maxVertices.value.to!string;
45         if (location != Location.init) lst ~= "location = " ~ location.value.to!string;
46         return "layout(" ~ lst.join(", ") ~ ")";
47     }
48 }
49 
50 string layout_attributes(T...)() {
51     string[] lst;
52     foreach (int i, immutable s; T) {
53         static if (is(s == Primitive)) lst ~= "qualifier: args[%d]".format(i);
54         else static if (is(s == MaxVertices)) lst ~= "maxVertices: args[%d]".format(i);
55         else static if (is(s == Location)) lst ~= "location: args[%d]".format(i);
56     }
57     return lst.join(",");
58 }
59 auto layout(T...)(T args) {
60     mixin("Layout l = {" ~ layout_attributes!T ~ "};");
61     return l;
62 }
63 @property auto max_vertices(int i) { return MaxVertices(i); }
64 @property auto location(int i) { return Location(i); }
65 
66 
67 class Shader(alias Type, int _version = 330, string file = __FILE__, int line = __LINE__) : ShaderBase {
68     static immutable glslVersion = _version;
69     static immutable filepath = file;
70     static immutable lineno = line;
71     mixin Type;
72 }
73 
74 mixin template Vertex() {
75     static assert(glslVersion >= 330, "You need at least GLSL version 330 for vertex shaders!");
76     static immutable type = "vertex";
77     vec4 gl_Position;
78 }
79 
80 mixin template Fragment() {
81     static assert(glslVersion >= 330, "You need at least GLSL version 330 for fragment shaders!");
82     static immutable type = "fragment";
83 }
84 
85 mixin template Geometry() {
86     static assert(glslVersion >= 330, "You need at least GLSL version 330 for geometry shaders!");
87     static immutable type = "geometry";
88     void EmitVertex() {};
89     void EndPrimitive() {};
90 
91     struct PerVertex {
92         vec4 gl_Position;
93         float gl_PointSize;
94         float[] gl_ClipDistance;
95     }
96     PerVertex[] gl_in;
97 
98     vec4 gl_Position;
99     float gl_PointSize;
100     float[] gl_ClipDistance;
101 
102     struct of {}
103 
104     enum {
105         points = Primitive("points"),
106         lines = Primitive("lines"),
107         lines_adjacency = Primitive("lines_adjacency"),
108         triangles = Primitive("triangles"),
109         triangles_adjacency = Primitive("triangles_adjacency"),
110         triangle_strip = Primitive("triangle_strip"),
111         line_strip = Primitive("line_strip")
112     }
113 }
114 
115 mixin template TessellationControl() {
116     static assert(glslVersion >= 400, "You need at least GLSL version 400 for tessellation control shaders!");
117     static immutable type = "tessellationControl";
118 }
119 
120 mixin template TessellationEvaluation() {
121     static assert(glslVersion >= 400, "You need at least GLSL version 400 for tessellation evaluation shaders!");
122     static immutable type = "tessellationEvaluation";
123 }
124 
125 mixin template Compute() {
126     static assert(glslVersion >= 430, "You need at least GLSL version 430 for compute shaders!");
127     static immutable type = "compute";
128 }
129 
130 
131 void compile(T : ShaderBase)(T shader) {
132     static if (T.type == "vertex")
133         GLuint id = glCreateShader(GL_VERTEX_SHADER);
134     static if (T.type == "fragment")
135         GLuint id = glCreateShader(GL_FRAGMENT_SHADER);
136     static if (T.type == "geometry")
137         GLuint id = glCreateShader(GL_GEOMETRY_SHADER);
138     static if (T.type == "tessellationControl")
139         GLuint id = glCreateShader(GL_GEOMETRY_SHADER);
140     static if (T.type == "tessellationEvaluation")
141         GLuint id = glCreateShader(GL_GEOMETRY_SHADER);
142     static if (T.type == "compute")
143         GLuint id = glCreateShader(GL_GEOMETRY_SHADER);
144 
145     auto src = dtoglsl!(T).toStringz;
146     shader._shaderid = id;
147     glShaderSource(id, 1, &src, null);
148     glCompileShader(id);
149     
150     GLint compiled;
151     glGetShaderiv(shader._shaderid, GL_COMPILE_STATUS, &compiled);
152     if (compiled == GL_FALSE) {
153         throw new Exception(infoLog(shader));
154     }
155 }
156 
157 /*
158 ** プログラムの情報を表示する
159 ** ref: http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090827
160 */
161 string infoLog(T : ShaderBase)(T shader) {
162     GLsizei bufSize;
163 
164     /* シェーダのコンパイル時のログの長さを取得する */
165     glGetShaderiv(shader._shaderid, GL_INFO_LOG_LENGTH , &bufSize);
166 
167     if (bufSize == 0) return "";
168     
169     GLchar[] infoLog = new GLchar[](bufSize);
170     GLsizei length;
171 
172     /* シェーダのコンパイル時のログの内容を取得する */
173     glGetShaderInfoLog(shader._shaderid, bufSize, &length, infoLog.ptr);
174     return format("InfoLog:\n%s\n", infoLog);
175 }