1 /++ Gives you access to all glFunctions, GL_CONSTANTS and GLtypes.
2 
3 In debug mode, glGetError() is automatically checked before and after all
4 calls to all glFunctions (except glGetError). Any errors are then thrown
5 as an moggle.core.gl.GLError.
6 
7 When not in debug mode, moggle.core.gl simply publicly imports the Derelict OpenGL modules.
8 
9 Don't forget to call loadOpenGL() after you created your OpenGL context,
10 or some glFunctions will still be null.
11 
12 The Derelict library is used for OpenGL bindings.
13 +/
14 module moggle.core.gl;
15 
16 import std.traits;
17 
18 import derelict.opengl3.gl3;
19 public import derelict.opengl3.types;
20 public import derelict.opengl3.constants;
21 
22 pragma(lib, "dl");
23 pragma(lib, "DerelictGL3");
24 pragma(lib, "DerelictUtil");
25 
26 static this() {
27 	DerelictGL3.load();
28 }
29 
30 /// Call this after creating your OpenGL context.
31 GLVersion loadOpenGL() {
32 	return DerelictGL3.reload();
33 }
34 
35 /// The error that is thrown when glGetError() indicates an error.
36 class GLError : Exception {
37 	this(string func, string what, string file = __FILE__, size_t line = __LINE__) {
38 		super(func ~ ": " ~ what, file, line);
39 	}
40 }
41 
42 debug {
43 	immutable string[uint] constant_names;
44 
45 	static this() {
46 		foreach (x; __traits(allMembers, derelict.opengl3.constants)) {
47 			static if (x[0..3] == "GL_") {
48 				if (mixin(x) !in constant_names) constant_names[mixin(x)] = x;
49 			}
50 		}
51 	}
52 
53 	void check_error(string file, size_t line, string func) {
54 		auto e = glGetError();
55 		if (e != GL_NO_ERROR) throw new GLError(func, constant_names[e], file, line);
56 	}
57 
58 	auto wrap(alias glSomething)(ParameterTypeTuple!glSomething parameters, string file = __FILE__, size_t line = __LINE__)
59 	in { check_error(file, line, "Before " ~ __traits(identifier, glSomething)); }
60 	out { check_error(file, line, __traits(identifier, glSomething)); }
61 	body { return glSomething(parameters); }
62 
63 	mixin((){
64 		string code;
65 		foreach (part, members; [
66 			"functions": [__traits(allMembers, derelict.opengl3.functions)],
67 			"arb": [__traits(allMembers, derelict.opengl3.arb)],
68 			"ext": [__traits(allMembers, derelict.opengl3.ext)]
69 		]) {
70 			foreach (x; members) {
71 				if (x[0..2] == "gl" && x != "glGetError") {
72 					code ~= "alias wrap!(derelict.opengl3." ~ part ~ "." ~ x ~ ") " ~ x ~ ";\n";
73 				} else if (x[0..2] == "GL" || x == "glGetError") {
74 					code ~= "alias derelict.opengl3." ~ part ~ "." ~ x ~ " " ~ x ~ ";\n";
75 				}
76 			}
77 		}
78 		return code;
79 	}());
80 
81 } else {
82 
83 	public import derelict.opengl3.functions;
84 	public import derelict.opengl3.arb;
85 	public import derelict.opengl3.ext;
86 
87 }
88 
89 /++ Get the GL_CONSTANT representing the type T.
90 
91 This is an alias of one of GL_FLOAT, GL_DOUBLE, GL_UNSIGNED_INT, GL_INT,
92 GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_BYTE, and GL_BYTE.
93 
94 Examples:
95 ---
96 assert(GL_type!float == GL_FLOAT);
97 ---
98 +/
99 template GL_type(T) {
100 	     static if (is(T == GLfloat )) alias GL_FLOAT          GL_type;
101 	else static if (is(T == GLdouble)) alias GL_DOUBLE         GL_type;
102 	else static if (is(T == GLubyte )) alias GL_UNSIGNED_BYTE  GL_type;
103 	else static if (is(T == GLbyte  )) alias GL_BYTE           GL_type;
104 	else static if (is(T == GLushort)) alias GL_UNSIGNED_SHORT GL_type;
105 	else static if (is(T == GLshort )) alias GL_SHORT          GL_type;
106 	else static if (is(T == GLuint  )) alias GL_UNSIGNED_INT   GL_type;
107 	else static if (is(T == GLint   )) alias GL_INT            GL_type;
108 }