1 /++
2 Module for loading the library of open graphics, as well as some of its 
3 extensions.
4 
5 Also, the module provides information about which version of the library 
6 is used, provides a list of available extensions, and more.
7 
8 To load the library, you need the created graphics context. Therefore, 
9 you need to create a window and embed a graphical context, 
10 which is described $(HREF window.html, here). After that, 
11 using the $(LREF loadGraphicsLibrary) function, the functions of 
12 the open graphics library will be available.
13 
14 Example:
15 ---
16 import tida.runtime;
17 import tida.window;
18 import tida.gl;
19 
20 int main(string[] args)
21 {
22     ITidaRuntime.initialize(args, AllLibrary);
23     Window window = new Window(640, 480, "Example window");
24     window.windowInitialize!(WithContext)();
25     
26     loadGraphicsLibrary();
27     
28     return 0;
29 }
30 ---
31 
32 Macros:
33     LREF = <a href="#$1">$1</a>
34     HREF = <a href="$1">$2</a>
35 
36 Authors: $(HREF https://github.com/TodNaz,TodNaz)
37 Copyright: Copyright (c) 2020 - 2021, TodNaz.
38 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT)
39 +/
40 module tida.gl;
41 
42 public import bindbc.opengl;
43 
44 __gshared int[2] _glVersionSpecifed;
45 __gshared string _glslVersion;
46 
47 /++
48 A function that returns the version of the library in the form of two numbers: 
49 a major version and a minor version.
50 +/
51 @property int[2] glVersionSpecifed() @trusted
52 {
53     return _glVersionSpecifed;
54 }
55 
56 /++
57 Indicates whether the use of geometry shaders is supported on this device.
58 +/
59 @property bool glGeometrySupport() @trusted
60 {
61     ExtList extensions = glExtensionsList();
62 	
63     return 	hasExtensions(extensions, Extensions.geometryShaderARB) ||
64             hasExtensions(extensions, Extensions.geometryShaderEXT) ||
65             hasExtensions(extensions, Extensions.geometryShaderNV);
66 }
67 
68 /++
69 Returns the maximum version of the shaders in the open graphics.
70 +/
71 @property string glslVersion() @trusted
72 {
73     return _glslVersion;
74 }
75 
76 @property uint glError() @trusted
77 {
78     return glGetError();
79 }
80 
81 @property string glErrorMessage(immutable uint err) @trusted
82 {
83     string error;
84 
85     switch (err)
86     {
87         case GL_INVALID_ENUM:
88             error = "Invalid enum!";
89             break;
90 
91         case GL_INVALID_VALUE:
92             error = "Invalid input value!";
93             break;
94 
95         case GL_INVALID_OPERATION:
96             error = "Invalid operation!";
97             break;
98 
99         case GL_STACK_OVERFLOW:
100             error = "Stack overflow!";
101             break;
102 
103         case GL_STACK_UNDERFLOW:
104             error = "Stack underflow!";
105             break;
106 
107         case GL_OUT_OF_MEMORY:
108             error = "Out of memory!";
109             break;
110 
111         case GL_INVALID_FRAMEBUFFER_OPERATION:
112             error = "Invalid framebuffer operation!";
113             break;
114 
115         default:
116             error = "Unkown error!";
117     }
118 
119     return error;
120 }
121 
122 void checkGLError(
123     string file = __FILE__,
124     size_t line = __LINE__,
125     string func = __FUNCTION__
126 ) @safe
127 {
128     immutable err = glError();
129     if (err != GL_NO_ERROR)
130     {
131         throw new Exception(
132             "In function `" ~ func ~ "` discovered error: `" ~ glErrorMessage(err) ~ "`.",
133             file,
134             line
135         );
136     }
137 }
138 
139 void assertGLError(
140     lazy uint checked,
141     string file = __FILE__,
142     size_t line = __LINE__,
143     string func = __FUNCTION__
144 ) @safe
145 {
146     immutable err = checked();
147     if (err != GL_NO_ERROR)
148     {
149         throw new Exception(
150             "In function `" ~ func ~ "` discovered error: `" ~ glErrorMessage(err) ~ "`.",
151             file,
152             line
153         );
154     }
155 }
156 
157 /++
158 Returns the company responsible for this GL implementation. 
159 This name does not change from release to release. 
160 
161 See_Also:
162     $(HREF https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetString.xhtml, OpenGL Reference - glGetString)
163 +/
164 @property string glVendor() @trusted
165 {
166     import std.conv : to;
167 	
168     return glGetString(GL_VENDOR).to!string;
169 }
170 
171 /++
172 Returns the name of the renderer. 
173 This name is typically specific to a particular configuration of a hardware platform. 
174 It does not change from release to release. 
175 
176 See_Also:
177     $(HREF https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetString.xhtml, OpenGL Reference - glGetString)
178 +/
179 @property string glRenderer() @trusted
180 {
181     import std.conv : to;
182 	
183     return glGetString(GL_RENDERER).to!string;
184 }
185 
186 /++
187 The function loads the `OpenGL` libraries for hardware graphics acceleration.
188 
189 Throws:
190 $(HREF https://dlang.org/library/object.html#Exception, Exception) 
191 if the library was not found or the context was not created to implement 
192 hardware acceleration.
193 +/
194 void loadGraphicsLibrary() @trusted
195 {
196     import std.exception : enforce;
197     import std.conv : to;
198 
199     bool valid(GLSupport value)
200     {
201         return value != GLSupport.noContext &&
202                value != GLSupport.badLibrary &&
203                value != GLSupport.noLibrary; 
204     }
205 
206     GLSupport retValue = loadOpenGL();
207     enforce!Exception(valid(retValue), 
208     "The library was not loaded or the context was not created!");
209 
210     glGetIntegerv(GL_MAJOR_VERSION, &_glVersionSpecifed[0]);
211     glGetIntegerv(GL_MINOR_VERSION, &_glVersionSpecifed[1]);
212    _glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION).to!string[0 .. 4];
213 }
214 
215 alias ExtList = string[];
216 
217 /++
218 Available extensions that the framework can load with one function.
219 +/
220 enum Extensions : string
221 {
222     /++
223     Compressing texture images can reduce texture memory utilization and
224     improve performance when rendering textured primitives.
225     
226     See_Also:
227         $(HREF https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression.txt, OpenGL reference "GL_ARB_texture_compression")
228     +/
229     textureCompression = "GL_ARB_texture_compression",
230     
231     /++
232     This extension introduces the notion of one- and two-dimensional array
233     textures.  An array texture is a collection of one- and two-dimensional
234     images of identical size and format, arranged in layers.
235     
236     See_Also:
237         $(HREF https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_array.txt, OpenGL reference "GL_EXT_texture_array")
238     +/
239     textureArray = "GL_EXT_texture_array",
240     
241     /++
242     Texture objects are fundamental to the operation of OpenGL. They are
243     used as a source for texture sampling and destination for rendering
244     as well as being accessed in shaders for image load/store operations
245     It is also possible to invalidate the contents of a texture. It is
246     currently only possible to set texture image data to known values by
247     uploading some or all of a image array from application memory or by
248     attaching it to a framebuffer object and using the Clear or ClearBuffer
249     commands.
250     
251     See_Also:
252         $(HREF https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_clear_texture.txt, OpenGL reference "GL_ARB_clear_texture")
253     +/
254     textureClear = "GL_ARB_clear_texture",
255     
256     /++
257     ARB_geometry_shader4 defines a new shader type available to be run on the
258     GPU, called a geometry shader. Geometry shaders are run after vertices are
259     transformed, but prior to color clamping, flat shading and clipping.
260     
261     See_Also:
262         $(HREF https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_geometry_shader4.txt, OpenGL reference "GL_ARB_geometry_shader4")
263     +/
264     geometryShaderARB = "GL_ARB_geometry_shader4",
265     
266     /// ditto
267     geometryShaderEXT = "GL_EXT_geometry_shader4",
268     
269     /// ditto
270     geometryShaderNV = "GL_NV_geometry_shader4"
271 }
272 
273 /++
274 Checks if the extension specified in the argument is in the open graphics library.
275 
276 Params:
277     list =  List of extensions. Leave it blank (using the following: '[]') 
278             for the function to calculate all the extensions by itself.
279     name =  The name of the extension you need.
280 
281 Returns:
282     Extension search result. `False` if not found.
283 +/
284 bool hasExtensions(ExtList list, string name) @trusted
285 {
286     import std.algorithm : canFind;
287 
288     if (list.length == 0)
289         list = glExtensionsList();
290 
291     return list.canFind(name);
292 }
293 
294 /++
295 A function that provides a list of available extensions to use.
296 +/
297 ExtList glExtensionsList() @trusted
298 {
299     import std.conv : to;
300     import std.string : split;
301 
302     int numExtensions = 0;
303     glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
304 
305     string[] extensions;
306 
307     foreach (i; 0 .. numExtensions)
308     {
309         extensions ~= glGetStringi(GL_EXTENSIONS, i).to!string;
310     }
311 
312     return extensions;
313 }
314 
315 // Texture compressed
316 alias FCompressedTexImage2DARB = extern(C) void function(GLenum target,
317                                                int level,
318                                                GLenum internalformat,
319                                                GLsizei width,
320                                                GLsizei height,
321                                                int border,
322                                                GLsizei imagesize,
323                                                void* data);
324 
325 __gshared
326 {
327     FCompressedTexImage2DARB glCompressedTexImage2DARB;
328 }
329 
330 alias glCompressedTexImage2D = glCompressedTexImage2DARB;
331 
332 enum
333 {
334     GL_COMPRESSED_RGBA_ARB = 0x84EE,
335     GL_COMPRESSED_RGB_ARB = 0x84ED,
336     GL_COMPRESSED_ALPHA_ARB = 0x84E9,
337 
338     GL_TEXTURE_COMPRESSION_HINT_ARB = 0x84EF,
339     GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB = 0x86A0,
340     GL_TEXTURE_COMPRESSED_ARB = 0x86A1,
341     GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB = 0x86A2,
342     GL_COMPRESSED_TEXTURE_FORMATS_ARB = 0x86A3
343 }
344 
345 /++
346 Loads the extension `GL_ARB_texture_compression`, that is, 
347 extensions for loading compressed textures.
348 
349 Returns:
350     Returns the result of loading. False if the download is not successful.
351 +/
352 bool extTextureCompressionLoad() @trusted
353 {
354     import bindbc.opengl.util;
355 
356     if (!hasExtensions(null, "GL_ARB_texture_compression"))
357         return false;
358 
359     if (!loadExtendedGLSymbol(  cast(void**) &glCompressedTexImage2DARB,
360                                 "glCompressedTexImage2DARB"))
361         return false;
362 
363     return true;
364 }
365 
366 // Texture array ext 
367 alias FFramebufferTextureLayerEXT = extern(C) void function();
368 
369 __gshared
370 {
371     FFramebufferTextureLayerEXT glFramebufferTextureLayerEXT;
372 }
373 
374 enum
375 {
376     GL_TEXTURE_1D_ARRAY_EXT = 0x8C18,
377     GL_TEXTURE_2D_ARRAY_EXT = 0x8C1A,
378 
379     GL_TEXTURE_BINDING_1D_ARRAY_EXT = 0x8C1C,
380     GL_TEXTURE_BINDING_2D_ARRAY_EXT = 0x8C1D,
381     GL_MAX_ARRAY_TEXTURE_LAYERS_EXT = 0x88FF,
382     GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT = 0x884E
383 }
384 
385 /++
386 Loads the extension `GL_EXT_texture_array`, that is, extensions for 
387 loading an array of textures.
388 
389 Returns:
390     Returns the result of loading. False if the download is not successful.
391 +/
392 bool extTextureArrayLoad() @trusted
393 {
394     import bindbc.opengl.util;
395 
396     if (!hasExtensions(null, Extensions.textureArray))
397         return false;
398 
399     // glFramebufferTextureLayerEXT
400     if (!loadExtendedGLSymbol(cast(void**) &glFramebufferTextureLayerEXT,
401                               "glFramebufferTextureLayerEXT"))
402         return false;
403 
404     return true;
405 }