1 /// OpenGL loader
2 module gfx.bindings.opengl.loader;
3 
4 // Dynamic bindings facility
5 
6 /// A handle to a shared library
7 alias SharedLib = void*;
8 /// A handle to a shared library symbol
9 alias SharedSym = void*;
10 
11 /// Opens a shared library.
12 /// Return null in case of failure.
13 SharedLib openSharedLib(string name);
14 
15 /// Load a symbol from a shared library.
16 /// Return null in case of failure.
17 SharedSym loadSharedSym(SharedLib lib, string name);
18 
19 /// Close a shared library
20 void closeSharedLib(SharedLib lib);
21 
22 
23 /// Generic Dynamic lib symbol loader.
24 /// Symbols loaded with such loader must be cast to the appropriate function type.
25 alias SymbolLoader = SharedSym delegate (in string name);
26 
27 
28 version(Posix)
29 {
30     import std.string : toStringz;
31     import core.sys.posix.dlfcn;
32 
33     SharedLib openSharedLib(string name)
34     {
35         return dlopen(toStringz(name), RTLD_LAZY);
36     }
37 
38     SharedSym loadSharedSym(SharedLib lib, string name)
39     {
40         return dlsym(lib, toStringz(name));
41     }
42 
43     void closeSharedLib(SharedLib lib)
44     {
45         dlclose(lib);
46     }
47 }
48 version(Windows)
49 {
50     import std.string : toStringz;
51     import core.sys.windows.winbase;
52 
53     SharedLib openSharedLib(string name)
54     {
55         return LoadLibraryA(toStringz(name));
56     }
57 
58     SharedSym loadSharedSym(SharedLib lib, string name)
59     {
60         return GetProcAddress(lib, toStringz(name));
61     }
62 
63     void closeSharedLib(SharedLib lib)
64     {
65         FreeLibrary(lib);
66     }
67 }
68 
69 /// Utility that open a shared library and load symbols from it.
70 class SharedLibLoader
71 {
72     import std.typecons : Flag, Yes, No;
73     private SharedLib _lib;
74     private string _libName;
75 
76     /// Load the shared libraries and call bindSymbols if succesful.
77     void load (string[] libNames)
78     {
79         foreach (ln; libNames)
80         {
81             _lib = openSharedLib(ln);
82             if (_lib)
83             {
84                 _libName = ln;
85                 break;
86             }
87         }
88         if (!_lib)
89         {
90             import std.conv : to;
91             throw new Exception(
92                 "Cannot load one of shared libs " ~ libNames.to!string
93             );
94         }
95         bindSymbols();
96     }
97 
98     /// Direct handle access
99     public @property SharedLib handle()
100     {
101         return _lib;
102     }
103 
104     /// Returns whether the shared library is open.
105     public @property bool loaded() const
106     {
107         return _lib !is null;
108     }
109 
110     /// Returns the name of the shared library that was open.
111     /// Empty string if not loaded.
112     public @property string libName() const
113     {
114         return _libName;
115     }
116 
117     /// Bind a symbol, using the function pointer symbol name.
118     void bind(alias f)(Flag!"optional" optional = No.optional)
119     {
120         immutable name = f.stringof;
121         if (f !is null)
122         {
123             throw new Exception("Tentative to bind already bound symbol "~ name);
124         }
125         auto sym = loadSharedSym(_lib, name);
126         if (!sym && !optional)
127         {
128             throw new Exception("Cannot load symbol "~name~" from "~_libName~".");
129         }
130         f = cast(typeof(f)) sym;
131     }
132 
133     /// Subclasses can override this to bind all the necessary symbols.
134     /// Default implementation does nothing.
135     void bindSymbols()
136     {}
137 }