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 }