1 
2 module dglsl.program;
3 
4 import std.string;
5 
6 import derelict.opengl3.gl3;
7 import gl3n.linalg : Vector, Matrix;
8 
9 import dglsl.gspl;
10 import dglsl.shader;
11 
12 
13 class Program(T...) {
14     private GLuint _programid;
15     @property auto id() const { return _programid; }
16 
17     mixin(shader_uniform!T);
18 
19     this(T shaders) {
20         _programid = glCreateProgram();
21 
22         foreach (s; shaders) {
23             glAttachShader(_programid, s.id);
24         }
25 
26         glLinkProgram(_programid);
27 
28         GLint linked;
29         glGetProgramiv(_programid, GL_LINK_STATUS, &linked);
30 
31         if (linked == GL_FALSE) {
32             throw new Exception(infoLog(this));
33         }
34 
35         setUniformLocations();
36     }
37 }
38 
39 /*
40 ** プログラムの情報を表示する
41 ** from: http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20090827
42 */
43 string infoLog(T...)(Program!T p)
44 {
45     GLsizei bufSize;
46 
47     /* シェーダのリンク時のログの長さを取得する */
48     glGetProgramiv(p.id, GL_INFO_LOG_LENGTH , &bufSize);
49 
50     if (bufSize == 0) return "";
51 
52     GLchar[] infoLog = new GLchar[](bufSize);
53     GLsizei length;
54 
55     /* シェーダのリンク時のログの内容を取得する */
56     glGetProgramInfoLog(p.id, bufSize, &length, infoLog.ptr);
57     return format("InfoLog:\n%s\n", infoLog);
58 }
59 
60 auto makeProgram(T...)(T shaders) {
61     return new Program!T(shaders);
62 }
63 
64 import std.typecons;
65 
66 Tuple!(string, string)[] shader_uniform_list(T: ShaderBase)() {
67     import std.traits;
68     Tuple!(string, string)[] lst;
69     foreach (immutable s; __traits(derivedMembers, T)) {
70         static if (!hasUDA!(__traits(getMember, T, s), ignore) && hasUDA!(__traits(getMember, T, s), uniform)) {
71             immutable type = typeof(__traits(getMember, T, s)).stringof;
72             lst ~= Tuple!(string, string)(s, (type.startsWith("Sampler")) ? "int" : type);
73         }
74     }
75     return lst;
76 }
77 
78 Tuple!(string, string)[] shader_uniform_list(T...)() if (T.length > 1) {
79     import std.algorithm;
80     auto ls = shader_uniform_list!(T[0]);
81     auto ls2 = shader_uniform_list!(T[1 .. $]);
82 
83     foreach (s; ls) {
84         if (!ls2.canFind(s)) ls2 ~= s;
85     }
86 
87     return ls2;
88 }
89 
90 
91 string shader_uniform(T...)() {
92     import std.algorithm;
93     string result = "";
94     auto lst = shader_uniform_list!T;
95 
96     foreach (sym; lst) {
97         result ~= "GLint %sLoc;\n".format(sym[0]);
98         result ~= "@property void %s(%s v) { glUniform(%sLoc, v); }\n".format(sym[0], sym[1], sym[0]);
99     }
100 
101     auto locs = lst
102         .map!(sym => "\t%sLoc = glGetUniformLocation(_programid, `%s`.toStringz);".format(sym[0], sym[0]))
103         .join("\n");
104 
105     result ~= "void setUniformLocations() {\n" ~ locs ~ "\n}\n";
106 
107     return result;
108 }