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 }