1 2 module dglsl.translator; 3 4 import std.range; 5 import std.string; 6 import std.traits; 7 import std.algorithm; 8 9 import dglsl.type; 10 import dglsl.sampler; 11 import dglsl.shader; 12 13 14 string dtoglsl(Shader)() if (Shader.type == "vertex") { 15 string result = "#version %s\n".format(Shader.glslVersion); 16 string[] functions; 17 18 foreach (immutable s; __traits(derivedMembers, Shader)) { 19 static if (!hasUDA!(__traits(getMember, Shader, s), ignore)) { 20 static if(is(typeof(__traits(getMember, Shader, s)) == function)) { 21 functions ~= s; 22 } else { 23 static if (hasUDA!(__traits(getMember, Shader, s), input)) { 24 static if (Shader.type == "vertex" && hasUDA!(__traits(getMember, Shader, s), Layout)) { 25 auto l = getUDAs!(__traits(getMember, Shader, s), Layout)[0]; 26 result ~= l.glsl ~ " "; 27 } 28 result ~= "in "; 29 } 30 31 static if (hasUDA!(__traits(getMember, Shader, s), output)) { 32 result ~= "out "; 33 } 34 35 static if (hasUDA!(__traits(getMember, Shader, s), uniform)) { 36 result ~= "uniform "; 37 } 38 39 result ~= "%s %s;\n".format(glslType!(typeof(__traits(getMember, Shader, s))), s); 40 } 41 } 42 } 43 44 result ~= copyFunctions!(Shader.filepath, Shader.lineno)(functions); 45 46 return result; 47 } 48 49 string dtoglsl(Shader)() if (Shader.type == "fragment") { 50 string result = "#version %s\n".format(Shader.glslVersion); 51 string[] functions; 52 53 foreach (immutable s; __traits(derivedMembers, Shader)) { 54 static if (!hasUDA!(__traits(getMember, Shader, s), ignore)) { 55 static if(is(typeof(__traits(getMember, Shader, s)) == function)) { 56 functions ~= s; 57 } else { 58 static if (hasUDA!(__traits(getMember, Shader, s), input)) { 59 static if (Shader.type == "vertex" && hasUDA!(__traits(getMember, Shader, s), Layout)) { 60 auto l = getUDAs!(__traits(getMember, Shader, s), Layout)[0]; 61 result ~= l.glsl ~ " "; 62 } 63 result ~= "in "; 64 } 65 66 static if (hasUDA!(__traits(getMember, Shader, s), output)) { 67 result ~= "out "; 68 } 69 70 static if (hasUDA!(__traits(getMember, Shader, s), uniform)) { 71 result ~= "uniform "; 72 } 73 74 result ~= "%s %s;\n".format(glslType!(typeof(__traits(getMember, Shader, s))), s); 75 } 76 } 77 } 78 79 80 result ~= copyFunctions!(Shader.filepath, Shader.lineno)(functions); 81 82 return result; 83 } 84 85 string dtoglsl(Shader)() if (Shader.type == "geometry") { 86 string result = "#version %s\n".format(Shader.glslVersion); 87 string[] functions; 88 89 static assert(__traits(hasMember, Shader, "_input"), "Geometry shaders need an '_input' member!"); 90 static assert(__traits(hasMember, Shader, "_output"), "Geometry shaders need an '_output' member!"); 91 static assert(__traits(hasMember, Shader, "gl_in"), "Geometry shaders need an 'gl_in' member!"); 92 93 auto input = getUDAs!(Shader._input, Layout)[0]; 94 result ~= input.glsl ~ " in;\n"; 95 auto o = getUDAs!(Shader._output, Layout)[0]; 96 result ~= o.glsl ~ " out;\n"; 97 98 foreach (immutable s; __traits(derivedMembers, Shader)) { 99 static if (s != typeof(Shader.gl_in[0]).stringof && !hasUDA!(__traits(getMember, Shader, s), ignore)) { 100 alias t = typeof(__traits(getMember, Shader, s)); 101 static if(is(t == function)) { 102 functions ~= s; 103 } else static if (s != "_input" && s != "_output") { 104 static if (hasUDA!(__traits(getMember, Shader, s), uniform)) { 105 result ~= "uniform "; 106 } 107 108 static if (hasUDA!(__traits(getMember, Shader, s), output)) { 109 result ~= "out "; 110 } 111 112 result ~= "%s %s;\n".format(glslType!(typeof(__traits(getMember, Shader, s))), s); 113 } 114 } 115 } 116 117 result ~= copyFunctions!(Shader.filepath, Shader.lineno)(functions); 118 119 return result; 120 } 121 122 string dtoglsl(Shader)() if (Shader.type == "tessellationControl") { 123 string result = "#version %s\n".format(Shader.glslVersion); 124 // TODO: 125 return result; 126 } 127 128 string dtoglsl(Shader)() if (Shader.type == "tessellationEvaluation") { 129 string result = "#version %s\n".format(Shader.glslVersion); 130 // TODO: 131 return result; 132 } 133 134 string dtoglsl(Shader)() if (Shader.type == "compute") { 135 string result = "#version %s\n".format(Shader.glslVersion); 136 // TODO: 137 return result; 138 } 139 140 private string copyFunctions(string filepath, int lineno)(string[] functions) { 141 import std.ascii; 142 auto source = import(filepath).lineSplitter.drop(lineno - 1); 143 string result; 144 int level = 0; 145 while (!source.empty && level >= 0) { 146 string line = source.front; 147 148 if (functions.any!((s) { 149 auto r = line.findSplit(s); 150 return !r[1].empty && !isAlphaNum(r[0][$ - 1]) && !isAlphaNum(r[2][0]); 151 })) { 152 int lvl = level; 153 while (!source.empty) { 154 if (source.front.canFind('{')) level++; 155 if (source.front.canFind('}')) { 156 level--; 157 if (level < lvl) break; 158 } 159 result ~= source.front ~ "\n"; 160 source.popFront(); 161 } 162 163 continue; 164 } 165 166 if (line.canFind('{')) level++; 167 if (line.canFind('}')) level--; 168 169 source.popFront(); 170 } 171 172 return result; 173 }