1 /// High level OpenGL D wrapper
2 module opengl.d;
3 
4 public
5 {
6 	import opengl.d.buffer;
7 	import opengl.d.program;
8 	import opengl.d.shader;
9 	import opengl.d.vertexarray;
10 }
11 
12 import opengl.gl4;
13 
14 /// Generates a static OpenGL boolean property (glEnable/glDisable)
15 mixin template glBoolProperty(GLenum value, string name)
16 {
17 	static bool enabled()
18 	{
19 		return glIsEnabled(value);
20 	}
21 
22 	static bool enabled(bool val)
23 	{
24 		if (val)
25 			glEnable(value);
26 		else
27 			glDisable(value);
28 		return val;
29 	}
30 }
31 
32 /// Wrapper "namespace" containing properties and stateless functions
33 struct GL
34 {
35 	@disable this();
36 
37 @nogc @system:
38 
39 	@property nothrow
40 	{
41 		mixin glBoolProperty!(GL_BLEND, "Blend") blend;
42 		alias enableBlend = blend.enabled; ///
43 		mixin glBoolProperty!(GL_COLOR_LOGIC_OP, "ColorLogicOperation") colorLogicOperation;
44 		alias enableColorLogicOperation = colorLogicOperation.enabled; ///
45 		mixin glBoolProperty!(GL_CULL_FACE, "CullFace") cullFace;
46 		alias enableCullFace = cullFace.enabled; ///
47 		mixin glBoolProperty!(GL_DEBUG_OUTPUT, "DebugOutput") debugOutput;
48 		alias enableDebugOutput = debugOutput.enabled; ///
49 		mixin glBoolProperty!(GL_DEBUG_OUTPUT_SYNCHRONOUS, "DebugOutputSync") debugOutputSync;
50 		alias enableDebugOutputSync = debugOutputSync.enabled; ///
51 		mixin glBoolProperty!(GL_DEPTH_CLAMP, "DepthClamp") depthClamp;
52 		alias enableDepthClamp = depthClamp.enabled; ///
53 		mixin glBoolProperty!(GL_DEPTH_TEST, "DepthTest") depthTest;
54 		alias enableDepthTest = depthTest.enabled; ///
55 		mixin glBoolProperty!(GL_DITHER, "Dither") dither;
56 		alias enableDither = dither.enabled; ///
57 		mixin glBoolProperty!(GL_FRAMEBUFFER_SRGB, "FramebufferSRGB") framebufferSRGB;
58 		alias enableFramebufferSRGB = framebufferSRGB.enabled; ///
59 		mixin glBoolProperty!(GL_LINE_SMOOTH, "LineSmooth") lineSmooth;
60 		alias enableLineSmooth = lineSmooth.enabled; ///
61 		mixin glBoolProperty!(GL_MULTISAMPLE, "Multisample") multisample;
62 		alias enableMultisample = multisample.enabled; ///
63 		mixin glBoolProperty!(GL_POLYGON_OFFSET_FILL, "PolygonOffsetFill") polygonOffsetFill;
64 		alias enablePolygonOffsetFill = polygonOffsetFill.enabled; ///
65 		mixin glBoolProperty!(GL_POLYGON_OFFSET_LINE, "PolygonOffsetLine") polygonOffsetLine;
66 		alias enablePolygonOffsetLine = polygonOffsetLine.enabled; ///
67 		mixin glBoolProperty!(GL_POLYGON_OFFSET_POINT, "PolygonOffsetPoint") polygonOffsetPoint;
68 		alias enablePolygonOffsetPoint = polygonOffsetPoint.enabled; ///
69 		mixin glBoolProperty!(GL_POLYGON_SMOOTH, "PolygonSmooth") polygonSmooth;
70 		alias enablePolygonSmooth = polygonSmooth.enabled; ///
71 		mixin glBoolProperty!(GL_PRIMITIVE_RESTART, "PrimitiveRestart") primitiveRestart;
72 		alias enablePrimitiveRestart = primitiveRestart.enabled; ///
73 		mixin glBoolProperty!(GL_PRIMITIVE_RESTART_FIXED_INDEX, "PrimitiveRestartFixedIndex") primitiveRestartFixedIndex;
74 		alias enablePrimitiveRestartFixedIndex = primitiveRestartFixedIndex.enabled; ///
75 		mixin glBoolProperty!(GL_RASTERIZER_DISCARD, "RasterizerDiscard") rasterizerDiscard;
76 		alias enableRasterizerDiscard = rasterizerDiscard.enabled; ///
77 		mixin glBoolProperty!(GL_SAMPLE_ALPHA_TO_COVERAGE, "SampleAlphaToCoverage") sampleAlphaToCoverage;
78 		alias enableSampleAlphaToCoverage = sampleAlphaToCoverage.enabled; ///
79 		mixin glBoolProperty!(GL_SAMPLE_ALPHA_TO_ONE, "SampleAlphaToOne") sampleAlphaToOne;
80 		alias enableSampleAlphaToOne = sampleAlphaToOne.enabled; ///
81 		mixin glBoolProperty!(GL_SAMPLE_COVERAGE, "SampleCoverage") bSampleCoverage;
82 		alias enableSampleCoverage = bSampleCoverage.enabled; ///
83 		mixin glBoolProperty!(GL_SAMPLE_SHADING, "SampleShading") sampleShading;
84 		alias enableSampleShading = sampleShading.enabled; ///
85 		mixin glBoolProperty!(GL_SCISSOR_TEST, "ScissorTest") scissorTest;
86 		alias enableScissorTest = scissorTest.enabled; ///
87 		mixin glBoolProperty!(GL_STENCIL_TEST, "StencilTest") stencilTest;
88 		alias enableStencilTest = stencilTest.enabled; ///
89 		mixin glBoolProperty!(GL_TEXTURE_CUBE_MAP_SEAMLESS, "TextureCubeMapSeamless") textureCubeMapSeamless;
90 		alias enableTextureCubeMapSeamless = textureCubeMapSeamless.enabled; ///
91 		mixin glBoolProperty!(GL_PROGRAM_POINT_SIZE, "ProgramPointSize") programPointSize;
92 		alias enableProgramPointSize = programPointSize.enabled; ///
93 
94 		/// Returns the current cull face mode.
95 		static CullFaceMode cullFaceMode()
96 		{
97 			int mode;
98 			glGetIntegerv(GL_CULL_FACE_MODE, &mode);
99 			return cast(CullFaceMode) mode;
100 		}
101 		/// Sets the current cull face mode.
102 		static CullFaceMode cullFaceMode(CullFaceMode val)
103 		{
104 			glCullFace(val);
105 			return val;
106 		}
107 
108 		/// Returns the direction of front faces.
109 		static FrontFaceDirection frontFace()
110 		{
111 			int dir;
112 			glGetIntegerv(GL_FRONT_FACE, &dir);
113 			return cast(FrontFaceDirection) dir;
114 		}
115 		/// Changes the front face direction.
116 		static FrontFaceDirection frontFace(FrontFaceDirection val)
117 		{
118 			glFrontFace(val);
119 			return val;
120 		}
121 
122 		/// Sets a callback for debug messages
123 		static DebugMessageCallback debugMessageCallback(DebugMessageCallback cb)
124 		{
125 			void* param = wrapDebugCallback(cb);
126 			glDebugMessageCallback(&debugMessageCallbackWrapper, param);
127 			return cb;
128 		}
129 
130 		/// Returns the current depth function.
131 		static DepthFunction depthFunc()
132 		{
133 			int func;
134 			glGetIntegerv(GL_DEPTH_FUNC, &func);
135 			return cast(DepthFunction) func;
136 		}
137 		/// Changes the current depth function.
138 		static DepthFunction depthFunc(DepthFunction val)
139 		{
140 			glDepthFunc(val);
141 			return val;
142 		}
143 
144 		/// Returns the current line width.
145 		static float lineWidth()
146 		{
147 			float width;
148 			glGetFloatv(GL_LINE_WIDTH, &width);
149 			return width;
150 		}
151 		/// Changes the current line width.
152 		static float lineWidth(float val)
153 		{
154 			glLineWidth(val);
155 			return val;
156 		}
157 
158 		/// Returns the primitive restart index.
159 		static uint primitiveRestartIndex()
160 		{
161 			int index;
162 			glGetIntegerv(GL_PRIMITIVE_RESTART_INDEX, &index);
163 			return cast(uint) index;
164 		}
165 		/// Changes the primitive restart index.
166 		static uint primitiveRestartIndex(uint val)
167 		{
168 			glPrimitiveRestartIndex(val);
169 			return val;
170 		}
171 
172 		/// Returns the minimum rate at which sample shading takes place.
173 		static float minSampleShading()
174 		{
175 			float width;
176 			glGetFloatv(GL_MIN_SAMPLE_SHADING_VALUE, &width);
177 			return width;
178 		}
179 		/// Changes the minimum rate at which sample shading takes place.
180 		static float minSampleShading(float val)
181 		{
182 			glMinSampleShading(val);
183 			return val;
184 		}
185 
186 		/// Returns the current point size.
187 		static float pointSize()
188 		{
189 			float size;
190 			glGetFloatv(GL_POINT_SIZE, &size);
191 			return size;
192 		}
193 		/// Changes the current point size.
194 		static float pointSize(float val)
195 		{
196 			glPointSize(val);
197 			return val;
198 		}
199 
200 		/// Returns the logical pixel operation for rendering.
201 		static LogicOp logicOp()
202 		{
203 			int op;
204 			glGetIntegerv(GL_LOGIC_OP_MODE, &op);
205 			return cast(LogicOp) op;
206 		}
207 		/// Changes the logical pixel operation for rendering.
208 		static LogicOp logicOp(LogicOp val)
209 		{
210 			glLogicOp(val);
211 			return val;
212 		}
213 	}
214 
215 	nothrow
216 	{
217 		///
218 		static void blendFunc(BlendingFactor sfactor, BlendingFactor dfactor)
219 		{
220 			glBlendFunc(sfactor, dfactor);
221 		}
222 		///
223 		static void blendFunc(uint buf, BlendingFactor sfactor, BlendingFactor dfactor)
224 		{
225 			glBlendFunci(buf, sfactor, dfactor);
226 		}
227 		///
228 		static void blendFunc(BlendingFactor srcRGB, BlendingFactor dstRGB,
229 				BlendingFactor srcAlpha, BlendingFactor dstAlpha)
230 		{
231 			glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
232 		}
233 		///
234 		static void blendFunc(uint buf, BlendingFactor srcRGB, BlendingFactor dstRGB,
235 				BlendingFactor srcAlpha, BlendingFactor dstAlpha)
236 		{
237 			glBlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
238 		}
239 
240 		///
241 		static void depthRange(float nearVal, float farVal)
242 		{
243 			glDepthRangef(nearVal, farVal);
244 		}
245 		///
246 		static void depthRange(double nearVal, double farVal)
247 		{
248 			glDepthRange(nearVal, farVal);
249 		}
250 
251 		///
252 		static void sampleCoverage(float value, bool invert)
253 		{
254 			glSampleCoverage(value, invert);
255 		}
256 
257 		///
258 		static void polygonOffset(float factor, float units)
259 		{
260 			glPolygonOffset(factor, units);
261 		}
262 
263 		///
264 		static void scissor(int x, int y, uint width, uint height)
265 		{
266 			glScissor(x, y, width, height);
267 		}
268 		///
269 		static void scissorIndexed(uint index, int left, int bottom, uint width, uint height)
270 		{
271 			glScissorIndexed(index, left, bottom, width, height);
272 		}
273 		///
274 		static void scissorIndexed(uint index, int[4] v)
275 		{
276 			glScissorIndexedv(index, v.ptr);
277 		}
278 		///
279 		static void scissorArray(uint index, int[4][] v)
280 		{
281 			glScissorArrayv(index, cast(GLsizei) v.length, cast(int*) v.ptr);
282 		}
283 
284 		///
285 		static void polygonMode(MaterialFace face, PolygonMode mode)
286 		{
287 			glPolygonMode(face, mode);
288 		}
289 
290 		///
291 		static void stencilFunc(StencilFunction func, int ref_, uint mask)
292 		{
293 			glStencilFunc(func, ref_, mask);
294 		}
295 
296 		///
297 		static void stencilOp(StencilOp sfail, StencilOp dpfail, StencilOp dppass)
298 		{
299 			glStencilOp(sfail, dpfail, dppass);
300 		}
301 
302 		///
303 		static void clear(ClearBufferMask mask)
304 		{
305 			glClear(mask);
306 		}
307 
308 		///
309 		static void debugMessageInsert(DebugSource source, DebugType type, uint id,
310 				DebugSeverity severity, string msg)
311 		{
312 			glDebugMessageInsert(source, type, id, severity,
313 					cast(GLsizei) msg.length, cast(char*) msg.ptr);
314 		}
315 	}
316 }
317 
318 alias BlendingFactor = BlendingFactorDest;
319 
320 ///
321 enum DebugSeverity
322 {
323 	/// for any GL error, dangerous undefined behaviour, or any shader compiler and linker errors
324 	high = GL_DEBUG_SEVERITY_HIGH,
325 	/// for severe performance warnings, GLSL or other shader compiler and linker warnings, and use of currently deprecated behaviour
326 	medium = GL_DEBUG_SEVERITY_MEDIUM,
327 	/// for performance warnings from redundant state changes and trivial undefined behaviour
328 	low = GL_DEBUG_SEVERITY_LOW,
329 	/// for any message which is not an error or performance concern
330 	notification = GL_DEBUG_SEVERITY_NOTIFICATION
331 }
332 
333 ///
334 enum DebugType
335 {
336 	/// for events that generated an error
337 	error = GL_DEBUG_TYPE_ERROR,
338 	/// for behaviour that has been marked for deprecation
339 	deprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
340 	/// for behaviour that is undefined according to the specification
341 	undefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
342 	/// for implementation-dependent performance warnings
343 	performance = GL_DEBUG_TYPE_PERFORMANCE,
344 	/// for the use of extensions or shaders in a way that is highly vendor-specific
345 	portability = GL_DEBUG_TYPE_PORTABILITY,
346 	/// for annotation of the command stream
347 	marker = GL_DEBUG_TYPE_MARKER,
348 	/// for entering a debug group with glPushDebugGroup
349 	pushGroup = GL_DEBUG_TYPE_PUSH_GROUP,
350 	/// for leaving a debug group with glPopDebugGroup
351 	popGroup = GL_DEBUG_TYPE_POP_GROUP,
352 	/// for events that don't fit any of the ones listed above
353 	other = GL_DEBUG_TYPE_OTHER
354 }
355 
356 ///
357 enum DebugSource
358 {
359 	/// for messages generated by the GL
360 	api = GL_DEBUG_SOURCE_API,
361 	/// for messages generated by the GLSL shader compiler of compilers for other extension-provided languages
362 	compiler = GL_DEBUG_SOURCE_SHADER_COMPILER,
363 	/// for messages generated by the window system, such as WGL or GLX
364 	windowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM,
365 	/// for messages generated by external debuggers or third-party middle-ware libraries
366 	thirdParty = GL_DEBUG_SOURCE_THIRD_PARTY,
367 	/// for messages generated by the application, such as through glDebugMessageInsert
368 	application = GL_DEBUG_SOURCE_APPLICATION,
369 	/// for messages that do not fit to any of the other sources
370 	other = GL_DEBUG_SOURCE_OTHER
371 }
372 
373 alias DebugMessageCallback = void delegate(DebugSource source, DebugType type,
374 		GLuint id, DebugSeverity severity, string message);
375 
376 private extern (C) void debugMessageCallbackWrapper(GLenum source, GLenum type,
377 		GLuint id, GLenum severity, GLsizei length, const(GLchar)* message, void* userParam)
378 {
379 	DebugMessageCallback cb = unwrapDebugCallback(userParam);
380 	string msg = message[0 .. length].idup;
381 	cb(cast(DebugSource) source, cast(DebugType) type, id, cast(DebugSeverity) severity, msg);
382 }
383 
384 private struct CallbackWrapper
385 {
386 	void* ctx;
387 	void* fn;
388 }
389 
390 private __gshared CallbackWrapper debugCallback;
391 
392 private void* wrapDebugCallback(DebugMessageCallback cb) @nogc @system nothrow
393 {
394 	debugCallback = CallbackWrapper(cb.ptr, cast(void*) cb.funcptr);
395 	return cast(void*)&debugCallback;
396 }
397 
398 private DebugMessageCallback unwrapDebugCallback(void* data) @nogc @system nothrow
399 {
400 	CallbackWrapper wrap = *(cast(CallbackWrapper*) data);
401 	DebugMessageCallback ret;
402 	ret.ptr = wrap.ctx;
403 	ret.funcptr = cast(typeof(ret.funcptr)) wrap.fn;
404 	return ret;
405 }