├── .gitignore
├── CMakeLists.txt
├── README.md
├── build
└── README.md
├── examples
├── 01_Triangle
│ └── 01_Triangle.c
├── 99_ARB_shaders
│ ├── 99_ARB_shaders.c
│ └── resources
│ │ ├── FragmentShader.txt
│ │ └── VertexShader.txt
└── glbExamplesCommon.c
├── glbind.h
├── resources
└── README.md
└── source
├── external
├── tinyxml2.cpp
└── tinyxml2.h
├── glbind_build.cpp
└── glbind_template.h
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | /build
3 | /docs
4 | /examples/_build
5 | /resources/*.xml
6 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.10)
2 |
3 | # Version.
4 | file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/glbind.h" GLBIND_VERSION_LINE REGEX "glbind - v[0-9]+\\.[0-9]+\\.[0-9]+")
5 |
6 | string(REGEX MATCH "v([0-9]+\\.[0-9]+\\.[0-9]+)" _ ${GLBIND_VERSION_LINE})
7 | set(GLBIND_VERSION ${CMAKE_MATCH_1})
8 |
9 | message(STATUS "glbind Version: ${GLBIND_VERSION}")
10 |
11 | project(glbind VERSION ${GLBIND_VERSION})
12 |
13 |
14 | # Options
15 | option(GLBIND_BUILD_EXAMPLES "Build glbind examples" OFF)
16 | option(GLBIND_BUILD_TESTS "Build glbind tests" OFF)
17 | option(GLBIND_BUILD_TOOLS "Build glbind tools" OFF)
18 | option(GLBIND_FORCE_CXX "Force compilation as C++" OFF)
19 | option(GLBIND_FORCE_C89 "Force compilation as C89" OFF)
20 |
21 |
22 | # Construct compiler options.
23 | set(COMPILE_OPTIONS)
24 |
25 | if(GLBIND_FORCE_CXX AND GLBIND_FORCE_C89)
26 | message(FATAL_ERROR "GLBIND_FORCE_CXX and GLBIND_FORCE_C89 cannot be enabled at the same time.")
27 | endif()
28 |
29 | if(GLBIND_FORCE_CXX)
30 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
31 | message(STATUS "Compiling as C++ (GNU/Clang)")
32 | list(APPEND COMPILE_OPTIONS -x c++)
33 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
34 | message(STATUS "Compiling as C++ (MSVC)")
35 | list(APPEND COMPILE_OPTIONS /TP)
36 | else()
37 | message(WARNING "GLBIND_FORCE_CXX is enabled but the compiler does not support it. Ignoring.")
38 | endif()
39 | endif()
40 |
41 | if(GLBIND_FORCE_C89)
42 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
43 | message(STATUS "Compiling as C89")
44 | list(APPEND COMPILE_OPTIONS -std=c89)
45 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
46 | message(WARNING "MSVC does not support forcing C89. GLBIND_FORCE_C89 ignored.")
47 | else()
48 | message(WARNING "GLBIND_FORCE_C89 is enabled but the compiler does not support it. Ingoring.")
49 | endif()
50 | endif()
51 |
52 | # Warnings
53 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
54 | list(APPEND COMPILE_OPTIONS -Wall -Wextra -Wpedantic)
55 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
56 | #list(APPEND COMPILE_OPTIONS /W4)
57 | endif()
58 |
59 |
60 | # Link libraries
61 | set(COMMON_LINK_LIBRARIES)
62 |
63 | if (UNIX)
64 | list(APPEND COMMON_LINK_LIBRARIES dl) # For dlopen(), etc. Most compilers will link to this by default, but some may not.
65 | list(APPEND COMMON_LINK_LIBRARIES pthread) # Some compilers will not link to pthread by default so list it here just in case.
66 | list(APPEND COMMON_LINK_LIBRARIES m)
67 |
68 | # If we're compiling for 32-bit ARM we need to link to -latomic.
69 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
70 | list(APPEND COMMON_LINK_LIBRARIES atomic)
71 | endif()
72 | endif()
73 |
74 |
75 | # Common interface
76 | add_library(glbind_common INTERFACE)
77 | target_compile_options(glbind_common INTERFACE ${COMPILE_OPTIONS})
78 | target_link_libraries (glbind_common INTERFACE ${COMMON_LINK_LIBRARIES})
79 |
80 | if (UNIX)
81 | target_link_libraries(glbind_common INTERFACE X11)
82 | endif()
83 |
84 |
85 | # Examples
86 | if (GLBIND_BUILD_EXAMPLES)
87 | add_executable(01_Triangle examples/01_Triangle/01_Triangle.c)
88 | target_link_libraries(01_Triangle glbind_common)
89 |
90 | add_executable(99_ARB_shaders examples/99_ARB_shaders/99_ARB_shaders.c)
91 | target_link_libraries(99_ARB_shaders glbind_common)
92 | endif()
93 |
94 | # Tools
95 | if (GLBIND_BUILD_TOOLS)
96 | add_executable(glbind_build source/glbind_build.cpp)
97 | target_link_libraries(glbind_build glbind_common)
98 | endif()
99 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
A single file OpenGL header and API loader.
2 |
3 |
4 |
5 |
6 |
7 |
8 | glbind includes a full implementation of the OpenGL headers (auto-generated from the OpenGL spec) so there's no need
9 | for the offical headers or SDK. Unlike the official headers, the platform-specific sections are all contained within
10 | the same file.
11 |
12 |
13 | Usage
14 | =====
15 | glbind is a single file library with no dependencies. There's no need to link to any libraries, nor do you need to
16 | include any other headers. Everything you need is included in `glbind.h`.
17 | ```c
18 | #define GLBIND_IMPLEMENTATION
19 | #include "glbind.h"
20 |
21 | int main()
22 | {
23 | GLenum result = glbInit(NULL, NULL);
24 | if (result != GL_NO_ERROR) {
25 | printf("Failed to initialize glbind.");
26 | return -1;
27 | }
28 |
29 | ...
30 |
31 | glClearColor(0, 0, 0, 0);
32 | glClear(GL_COLOR_BUFFER_BIT);
33 |
34 | ...
35 |
36 | glbUninit();
37 | return 0;
38 | }
39 | ```
40 | The example above binds everything to global scope and uses default settings for the internal rendering context. You
41 | can also initialize glbind like the code below.
42 | ```c
43 | GLBapi gl;
44 | GLBconfig config = glbConfigInit();
45 | config.singleBuffered = GL_TRUE; /* Don't use double-buffering on the internal rendering context. */
46 | GLenum result = glbInit(&gl, &config);
47 | if (result != GL_NO_ERROR) {
48 | ... error initializing glbind ...
49 | }
50 |
51 | #if defined(GLBIND_WGL)
52 | HGLRC hRC = glbGetRC();
53 | ... do something with hRC ...
54 | #endif
55 |
56 | #if defined(GLBIND_GLX)
57 | GLXContext rc = glbGetRC();
58 | ... do something with rc ...
59 | #endif
60 |
61 | /* Draw something using local function pointers in the "gl" object instead of global scope. */
62 | gl.glClearColor(0, 0, 0, 0);
63 | gl.glClear(GL_COLOR_BUFFER_BIT);
64 | ```
65 | Since OpenGL requires a rendering context in order to retrieve function pointers, it makes sense to give the client
66 | access to it so they can avoid wasting time and memory creating their own rendering context unnecessarily. Therefore,
67 | glbind allows you to configure the internal rendering context and retrieve a handle to it so the application can
68 | make use of it.
69 |
70 | You can also initialize a `GLBapi` object against the current context (previously set with wglMakeCurrent or
71 | glXMakeCurrent) using `glbInitContextAPI()` or `glbInitCurrentContextAPI()`. Note, however, that before calling these
72 | functions you must have previously called `glbInit()`. These also do not automatically bind anything to global scope.
73 |
74 | You can explicitly bind the function pointers in a `GLBapi` object to global scope by using `glbBindAPI()`.
75 |
76 | License
77 | =======
78 | Public domain or MIT-0 (No Attribution). Choose whichever you prefer.
--------------------------------------------------------------------------------
/build/README.md:
--------------------------------------------------------------------------------
1 | When running the build tool, make sure it's run from the "bin" directory. The program will use hard coded relative
2 | paths when loading and writing files.
3 |
4 | You will need curl in the bin directory in order to run the build tool. This is required to download the XML files.
--------------------------------------------------------------------------------
/examples/01_Triangle/01_Triangle.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define GLBIND_IMPLEMENTATION
4 | #include "../../glbind.h"
5 |
6 | void Render(void)
7 | {
8 | glClearColor(0.2f, 0.5f, 0.8f, 0);
9 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
10 |
11 | glBegin(GL_TRIANGLES);
12 | {
13 | glColor3f(1, 0, 0);
14 | glVertex2f( 0.0f, +0.5f);
15 | glColor3f(0, 1, 0);
16 | glVertex2f(-0.5f, -0.5f);
17 | glColor3f(0, 0, 1);
18 | glVertex2f(+0.5f, -0.5f);
19 | }
20 | glEnd();
21 | }
22 |
23 | #if defined(GLBIND_WGL)
24 | static LRESULT DefaultWindowProcWin32(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
25 | {
26 | switch (msg)
27 | {
28 | case WM_CLOSE:
29 | {
30 | PostQuitMessage(0);
31 | } break;
32 |
33 | case WM_SIZE:
34 | {
35 | glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
36 | }
37 |
38 | default: break;
39 | }
40 |
41 | return DefWindowProcA(hWnd, msg, wParam, lParam);
42 | }
43 | #endif
44 |
45 | int main(int argc, char** argv)
46 | {
47 | GLBapi gl;
48 | GLenum result = glbInit(&gl, NULL);
49 | if (result != GL_NO_ERROR) {
50 | printf("Failed to initialize glbind.\n");
51 | return result;
52 | }
53 |
54 | glbBindAPI(&gl); /* Bind the API to global scope. */
55 |
56 | /* Create the window and show something on the screen. */
57 | {
58 | #if defined(GLBIND_WGL)
59 | WNDCLASSEXA wc;
60 | DWORD dwExStyle = 0;
61 | DWORD dwStyle = WS_OVERLAPPEDWINDOW;
62 | HWND hWnd;
63 |
64 | ZeroMemory(&wc, sizeof(wc));
65 | wc.cbSize = sizeof(wc);
66 | wc.cbWndExtra = sizeof(void*);
67 | wc.lpfnWndProc = (WNDPROC)DefaultWindowProcWin32;
68 | wc.lpszClassName = "GLBIND_01_Triangle";
69 | wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(32512));
70 | wc.style = CS_OWNDC | CS_DBLCLKS;
71 | if (!RegisterClassExA(&wc)) {
72 | printf("Failed to register window class.\n");
73 | return -1;
74 | }
75 |
76 | hWnd = CreateWindowExA(dwExStyle, "GLBIND_01_Triangle", "glbind 01_Triangle", dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, NULL, NULL);
77 | if (hWnd == NULL) {
78 | printf("Failed to create Win32 window.\n");
79 | return -1;
80 | }
81 |
82 | SetPixelFormat(GetDC(hWnd), glbGetPixelFormat(), glbGetPFD());
83 |
84 | ShowWindow(hWnd, SW_SHOWNORMAL);
85 |
86 | gl.wglMakeCurrent(GetDC(hWnd), glbGetRC()); /* Using the local API to avoid the need to link to OpenGL32.dll. */
87 |
88 | for (;;) {
89 | MSG msg;
90 | while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
91 | if (msg.message == WM_QUIT) {
92 | return (int)msg.wParam;
93 | }
94 |
95 | TranslateMessage(&msg);
96 | DispatchMessageA(&msg);
97 | }
98 |
99 | Render();
100 | SwapBuffers(GetDC(hWnd));
101 | }
102 |
103 | DestroyWindow(hWnd);
104 | #endif
105 |
106 | #if defined(GLBIND_GLX)
107 | XSetWindowAttributes attr;
108 | Display* pDisplay;
109 | Window windowX11;
110 | XVisualInfo* pVisualInfo = glbGetFBVisualInfo();
111 | Atom g_WM_DELETE_WINDOW = 0;
112 |
113 | pDisplay = glbGetDisplay();
114 | pVisualInfo = glbGetFBVisualInfo();
115 | g_WM_DELETE_WINDOW = XInternAtom(pDisplay, "WM_DELETE_WINDOW", False);
116 |
117 | attr.colormap = glbGetColormap();
118 | attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask | VisibilityChangeMask;
119 |
120 | windowX11 = XCreateWindow(pDisplay, XRootWindow(pDisplay, pVisualInfo->screen), 0, 0, 640, 480, 0, pVisualInfo->depth, InputOutput, pVisualInfo->visual, CWColormap | CWEventMask, &attr);
121 | if (windowX11 == 0) {
122 | printf("Failed to create X11 window.\n");
123 | return -1;
124 | }
125 |
126 | XSetWMProtocols(pDisplay, windowX11, &g_WM_DELETE_WINDOW, 1);
127 | XStoreName(pDisplay, windowX11, "glbind 01_Triangle");
128 | XMapRaised(pDisplay, windowX11); /* <-- Show the window. */
129 |
130 | gl.glXMakeCurrent(pDisplay, windowX11, glbGetRC());
131 |
132 | /* Set the initial viewport size. Use the size from the window. */
133 | XWindowAttributes windowAttributes;
134 | XGetWindowAttributes(pDisplay, windowX11, &windowAttributes);
135 |
136 | /* Now set the viewport. */
137 | glViewport(0, 0, windowAttributes.width, windowAttributes.height);
138 |
139 | /* Loop. */
140 | for (;;) {
141 | if (XPending(pDisplay) > 0) {
142 | XEvent x11Event;
143 | XNextEvent(pDisplay, &x11Event);
144 |
145 | if (x11Event.type == ClientMessage) {
146 | if ((Atom)x11Event.xclient.data.l[0] == g_WM_DELETE_WINDOW) {
147 | return 0; /* Received a quit message. */
148 | }
149 | };
150 |
151 | /* Handle events here. */
152 | } else {
153 | Render();
154 | gl.glXSwapBuffers(pDisplay, windowX11);
155 | }
156 | }
157 |
158 | /* Shutdown. */
159 | XDestroyWindow(pDisplay, windowX11);
160 | #endif
161 | }
162 |
163 | glbUninit();
164 |
165 | (void)argc;
166 | (void)argv;
167 | return 0;
168 | }
169 |
--------------------------------------------------------------------------------
/examples/99_ARB_shaders/99_ARB_shaders.c:
--------------------------------------------------------------------------------
1 | #include "../glbExamplesCommon.c"
2 |
3 | GLuint g_VertShader;
4 | GLuint g_FragShader;
5 |
6 | #define VERTEX_ATTRIB_POSITION 0
7 | #define VERTEX_ATTRIB_COLOR 1
8 |
9 | const void* vfs_map_file(const char* pFilePath, size_t* pFileSizeInBytes);
10 |
11 | static GLenum CreateShader(GLBexample* pExample, GLenum shaderTarget, const char* pShaderString, size_t shaderStringLength, GLuint* pShaderObject)
12 | {
13 | GLint shaderErrorPos;
14 |
15 | (void)pExample;
16 |
17 | /* Generate shader object. */
18 | glGenProgramsARB(1, pShaderObject);
19 | glBindProgramARB(shaderTarget, *pShaderObject);
20 |
21 | /* Load and compile. */
22 | glProgramStringARB(shaderTarget, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)shaderStringLength, pShaderString);
23 |
24 | /* Check for any errors. */
25 | glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &shaderErrorPos);
26 | if (shaderErrorPos != -1) {
27 | printf("Error in %s shader at position %d: ", (shaderTarget == GL_VERTEX_PROGRAM_ARB) ? "vertex" : "fragment", shaderErrorPos);
28 | printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
29 | return GL_INVALID_VALUE;
30 | }
31 |
32 | return GL_NO_ERROR;
33 | }
34 |
35 | static GLenum CreateShaders(GLBexample* pExample)
36 | {
37 | GLenum result;
38 | const void* pVertShaderString;
39 | size_t vertShaderStringLen;
40 | const void* pFragShaderString;
41 | size_t fragShaderStringLen;
42 |
43 | pVertShaderString = vfs_map_file("VertexShader.txt", &vertShaderStringLen);
44 | if (pVertShaderString == NULL) {
45 | printf("Failed to load vertex shader.\n");
46 | return GL_INVALID_VALUE;
47 | }
48 |
49 | pFragShaderString = vfs_map_file("FragmentShader.txt", &fragShaderStringLen);
50 | if (pVertShaderString == NULL) {
51 | printf("Failed to load fragment shader.\n");
52 | return GL_INVALID_VALUE;
53 | }
54 |
55 | result = CreateShader(pExample, GL_VERTEX_PROGRAM_ARB, pVertShaderString, vertShaderStringLen, &g_VertShader);
56 | if (result != GL_NO_ERROR) {
57 | return result;
58 | }
59 |
60 | result = CreateShader(pExample, GL_FRAGMENT_PROGRAM_ARB, pFragShaderString, fragShaderStringLen, &g_FragShader);
61 | if (result != GL_NO_ERROR) {
62 | glDeleteProgramsARB(1, &g_VertShader);
63 | return result;
64 | }
65 |
66 | return GL_NO_ERROR;
67 | }
68 |
69 | GLenum onInit(GLBexample* pExample)
70 | {
71 | GLenum result;
72 |
73 | /* We first need to check that we support ARB shaders. */
74 | if (!glbIsExtensionSupported(&pExample->gl, "GL_ARB_vertex_program")) {
75 | printf("GL_ARB_vertex_program not supported.\n");
76 | return GL_INVALID_OPERATION;
77 | }
78 | if (!glbIsExtensionSupported(&pExample->gl, "GL_ARB_fragment_program")) {
79 | printf("GL_ARB_fragment_program not supported.\n");
80 | return GL_INVALID_OPERATION;
81 | }
82 |
83 | result = CreateShaders(pExample);
84 | if (result != GL_NO_ERROR) {
85 | return result;
86 | }
87 |
88 | /* Shaders have been created. Initialize some state. */
89 | glEnable(GL_VERTEX_PROGRAM_ARB);
90 | glEnable(GL_FRAGMENT_PROGRAM_ARB);
91 |
92 | return GL_NO_ERROR;
93 | }
94 |
95 | void onDraw(GLBexample* pExample)
96 | {
97 | (void)pExample;
98 |
99 | glClearColor(0.2f, 0.5f, 0.8f, 0);
100 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
101 |
102 | /* Not strictly necessary in this example because they're already bound from the initialization stage, but explicitly bind the shaders first. */
103 | glBindProgramARB(GL_VERTEX_PROGRAM_ARB, g_VertShader);
104 | glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_FragShader);
105 |
106 | /* We can now set the MVP matrix. In this example we always use the identity matrix, but in a real program you would make this a variable. */
107 | glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, 1, 0, 0, 0);
108 | glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 1, 0, 1, 0, 0);
109 | glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 2, 0, 0, 1, 0);
110 | glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 3, 0, 0, 0, 1);
111 |
112 | glBegin(GL_TRIANGLES);
113 | {
114 | glVertexAttrib3f(VERTEX_ATTRIB_COLOR, 1, 0, 0);
115 | glVertexAttrib2f(VERTEX_ATTRIB_POSITION, 0.0f, 0.5f);
116 | glVertexAttrib3f(VERTEX_ATTRIB_COLOR, 0, 1, 0);
117 | glVertexAttrib2f(VERTEX_ATTRIB_POSITION, -0.5f, -0.5f);
118 | glVertexAttrib3f(VERTEX_ATTRIB_COLOR, 0, 0, 1);
119 | glVertexAttrib2f(VERTEX_ATTRIB_POSITION, 0.5f, -0.5f);
120 | }
121 | glEnd();
122 | }
123 |
124 | void onSize(GLBexample* pExample, GLsizei sizeX, GLsizei sizeY)
125 | {
126 | pExample->gl.glViewport(0, 0, sizeX, sizeY);
127 | }
128 |
129 | int main(int argc, char** argv)
130 | {
131 | GLenum result;
132 | GLBexampleconfig config;
133 | GLBexample example;
134 |
135 | (void)argc;
136 | (void)argv;
137 |
138 | config = glbExampleDefaultConfig();
139 | config.pWindowTitle = "ARB Shaders Example";
140 | config.windowSizeX = 640;
141 | config.windowSizeY = 480;
142 | config.onInit = onInit;
143 | config.onDraw = onDraw;
144 | config.onSize = onSize;
145 |
146 | result = glbExampleInit(&example, &config);
147 | if (result != GL_NO_ERROR) {
148 | printf("Failed to initialize example.\n");
149 | return -1;
150 | }
151 |
152 | glbExampleRun(&example);
153 |
154 | /* Done. */
155 | glbExampleUninit(&example);
156 | return 0;
157 | }
158 |
159 |
160 | static unsigned char g_vfsFileData[] = {
161 | 0x21, 0x21, 0x41, 0x52, 0x42, 0x66, 0x70, 0x31, 0x2E, 0x30, 0x0A, 0x0A, 0x23, 0x20, 0x49, 0x6E,
162 | 0x70, 0x75, 0x74, 0x73, 0x0A, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x20, 0x69, 0x43, 0x6F, 0x6C,
163 | 0x20, 0x3D, 0x20, 0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x74, 0x65, 0x78, 0x63,
164 | 0x6F, 0x6F, 0x72, 0x64, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x0A, 0x23, 0x20, 0x4F, 0x75, 0x74, 0x70,
165 | 0x75, 0x74, 0x73, 0x0A, 0x4F, 0x55, 0x54, 0x50, 0x55, 0x54, 0x20, 0x6F, 0x43, 0x6F, 0x6C, 0x20,
166 | 0x3D, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x2E, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3B, 0x0A,
167 | 0x0A, 0x4D, 0x4F, 0x56, 0x20, 0x6F, 0x43, 0x6F, 0x6C, 0x2C, 0x20, 0x69, 0x43, 0x6F, 0x6C, 0x3B,
168 | 0x0A, 0x0A, 0x45, 0x4E, 0x44, 0x00, 0x00, 0x00, 0x21, 0x21, 0x41, 0x52, 0x42, 0x76, 0x70, 0x31,
169 | 0x2E, 0x30, 0x0A, 0x0A, 0x23, 0x20, 0x49, 0x6E, 0x70, 0x75, 0x74, 0x73, 0x0A, 0x41, 0x54, 0x54,
170 | 0x52, 0x49, 0x42, 0x20, 0x69, 0x50, 0x6F, 0x73, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65,
171 | 0x78, 0x2E, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x41, 0x54, 0x54,
172 | 0x52, 0x49, 0x42, 0x20, 0x69, 0x43, 0x6F, 0x6C, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65,
173 | 0x78, 0x2E, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x0A, 0x23, 0x20,
174 | 0x4F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x0A, 0x4F, 0x55, 0x54, 0x50, 0x55, 0x54, 0x20, 0x6F,
175 | 0x50, 0x6F, 0x73, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x2E, 0x70, 0x6F, 0x73,
176 | 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x3B, 0x0A, 0x4F, 0x55, 0x54, 0x50, 0x55, 0x54, 0x20, 0x6F, 0x43,
177 | 0x6F, 0x6C, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x2E, 0x74, 0x65, 0x78, 0x63,
178 | 0x6F, 0x6F, 0x72, 0x64, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x0A, 0x23, 0x20, 0x55, 0x6E, 0x69, 0x66,
179 | 0x6F, 0x72, 0x6D, 0x73, 0x0A, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x20, 0x6D, 0x76, 0x70, 0x5B, 0x34,
180 | 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x2E, 0x6C, 0x6F,
181 | 0x63, 0x61, 0x6C, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x2E,
182 | 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61,
183 | 0x6D, 0x2E, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5B, 0x32, 0x5D, 0x2C, 0x20, 0x70, 0x72, 0x6F, 0x67,
184 | 0x72, 0x61, 0x6D, 0x2E, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5B, 0x33, 0x5D, 0x20, 0x7D, 0x3B, 0x0A,
185 | 0x0A, 0x44, 0x50, 0x34, 0x20, 0x6F, 0x50, 0x6F, 0x73, 0x2E, 0x78, 0x2C, 0x20, 0x69, 0x50, 0x6F,
186 | 0x73, 0x2C, 0x20, 0x6D, 0x76, 0x70, 0x5B, 0x30, 0x5D, 0x3B, 0x0D, 0x0A, 0x44, 0x50, 0x34, 0x20,
187 | 0x6F, 0x50, 0x6F, 0x73, 0x2E, 0x79, 0x2C, 0x20, 0x69, 0x50, 0x6F, 0x73, 0x2C, 0x20, 0x6D, 0x76,
188 | 0x70, 0x5B, 0x31, 0x5D, 0x3B, 0x0D, 0x0A, 0x44, 0x50, 0x34, 0x20, 0x6F, 0x50, 0x6F, 0x73, 0x2E,
189 | 0x7A, 0x2C, 0x20, 0x69, 0x50, 0x6F, 0x73, 0x2C, 0x20, 0x6D, 0x76, 0x70, 0x5B, 0x32, 0x5D, 0x3B,
190 | 0x0D, 0x0A, 0x44, 0x50, 0x34, 0x20, 0x6F, 0x50, 0x6F, 0x73, 0x2E, 0x77, 0x2C, 0x20, 0x69, 0x50,
191 | 0x6F, 0x73, 0x2C, 0x20, 0x6D, 0x76, 0x70, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x4D, 0x4F, 0x56,
192 | 0x20, 0x6F, 0x43, 0x6F, 0x6C, 0x2C, 0x20, 0x69, 0x43, 0x6F, 0x6C, 0x3B, 0x0A, 0x0A, 0x45, 0x4E,
193 | 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
194 | };
195 |
196 | typedef struct
197 | {
198 | const char* pFilePath;
199 | size_t sizeInBytes;
200 | size_t dataOffsetInBytes;
201 | } vfs_file_data;
202 |
203 | static vfs_file_data g_vfsCentralDirectory[] = {
204 | {"FragmentShader.txt", 117, 0},
205 | {"VertexShader.txt", 393, 120}
206 | };
207 |
208 | static size_t vfs_find_file(const char* pFilePath)
209 | {
210 | size_t iFile;
211 |
212 | if (pFilePath == NULL) {
213 | return (size_t)-1;
214 | }
215 |
216 | for (iFile = 0; iFile < sizeof(g_vfsCentralDirectory)/sizeof(g_vfsCentralDirectory[0]); iFile += 1) {
217 | int cmpresult = strcmp(g_vfsCentralDirectory[iFile].pFilePath, pFilePath);
218 | if (cmpresult == 0) {
219 | return iFile;
220 | }
221 | }
222 |
223 | return (size_t)-1;
224 | }
225 |
226 | const void* vfs_map_file(const char* pFilePath, size_t* pFileSizeInBytes)
227 | {
228 | size_t iFile;
229 |
230 | if (pFileSizeInBytes != NULL) {
231 | *pFileSizeInBytes = 0;
232 | }
233 |
234 | iFile = vfs_find_file(pFilePath);
235 | if (iFile == (size_t)-1) {
236 | return NULL;
237 | }
238 |
239 | if (pFileSizeInBytes != NULL) {
240 | *pFileSizeInBytes = g_vfsCentralDirectory[iFile].sizeInBytes;
241 | }
242 |
243 | return &g_vfsFileData[g_vfsCentralDirectory[iFile].dataOffsetInBytes];
244 | }
245 |
--------------------------------------------------------------------------------
/examples/99_ARB_shaders/resources/FragmentShader.txt:
--------------------------------------------------------------------------------
1 | !!ARBfp1.0
2 |
3 | # Inputs
4 | ATTRIB iCol = fragment.texcoord[0];
5 |
6 | # Outputs
7 | OUTPUT oCol = result.color;
8 |
9 | MOV oCol, iCol;
10 |
11 | END
--------------------------------------------------------------------------------
/examples/99_ARB_shaders/resources/VertexShader.txt:
--------------------------------------------------------------------------------
1 | !!ARBvp1.0
2 |
3 | # Inputs
4 | ATTRIB iPos = vertex.attrib[0];
5 | ATTRIB iCol = vertex.attrib[1];
6 |
7 | # Outputs
8 | OUTPUT oPos = result.position;
9 | OUTPUT oCol = result.texcoord[0];
10 |
11 | # Uniforms
12 | PARAM mvp[4] = { program.local[0], program.local[1], program.local[2], program.local[3] };
13 |
14 | DP4 oPos.x, iPos, mvp[0];
15 | DP4 oPos.y, iPos, mvp[1];
16 | DP4 oPos.z, iPos, mvp[2];
17 | DP4 oPos.w, iPos, mvp[3];
18 |
19 | MOV oCol, iCol;
20 |
21 | END
--------------------------------------------------------------------------------
/examples/glbExamplesCommon.c:
--------------------------------------------------------------------------------
1 | #define GLBIND_IMPLEMENTATION
2 | #include "../glbind.h"
3 |
4 | #include
5 | #include /* For strcmp() */
6 |
7 | typedef struct GLBexample GLBexample;
8 | typedef GLenum (* GLBOnInitProc) (GLBexample* pExample);
9 | typedef void (* GLBOnUninitProc)(GLBexample* pExample);
10 | typedef void (* GLBOnDrawProc) (GLBexample* pExample);
11 | typedef void (* GLBOnSizeProc) (GLBexample* pExample, GLsizei sizeX, GLsizei sizeY);
12 |
13 | typedef struct
14 | {
15 | GLBconfig* pGLBConfig;
16 | const char* pWindowTitle;
17 | GLsizei windowSizeX;
18 | GLsizei windowSizeY;
19 | void* pUserData;
20 | GLBOnInitProc onInit;
21 | GLBOnUninitProc onUninit;
22 | GLBOnDrawProc onDraw;
23 | GLBOnSizeProc onSize;
24 | } GLBexampleconfig;
25 |
26 | GLBexampleconfig glbExampleDefaultConfig(void)
27 | {
28 | GLBexampleconfig config;
29 |
30 | glbZeroObject(&config);
31 | config.pWindowTitle = "glbind Example";
32 | config.windowSizeX = 640;
33 | config.windowSizeY = 480;
34 |
35 | return config;
36 | }
37 |
38 |
39 | struct GLBexample
40 | {
41 | GLBapi gl;
42 | GLBexampleconfig config;
43 | GLboolean hasInitBeenCalled; /* This is used to ensure onSize is not called before initialization. */
44 | GLsizei windowSizeX;
45 | GLsizei windowSizeY;
46 | #if defined(GLBIND_WGL)
47 | struct
48 | {
49 | HWND hWnd;
50 | } win32;
51 | #else
52 | struct
53 | {
54 | Display* pDisplay;
55 | Window window;
56 | Atom WM_DELETE_WINDOW;
57 | } x11;
58 | #endif
59 | };
60 |
61 | static GLenum glbExample_OnInit(GLBexample* pExample)
62 | {
63 | GLenum result;
64 |
65 | if (pExample == NULL) {
66 | return GL_INVALID_VALUE;
67 | }
68 |
69 | if (pExample->config.onInit) {
70 | result = pExample->config.onInit(pExample);
71 | } else {
72 | result = GL_NO_ERROR;
73 | }
74 |
75 | pExample->hasInitBeenCalled = GL_TRUE;
76 |
77 | return result;
78 | }
79 |
80 | static void glbExample_OnSize(GLBexample* pExample, GLsizei sizeX, GLsizei sizeY)
81 | {
82 | if (pExample == NULL) {
83 | return;
84 | }
85 |
86 | pExample->windowSizeX = sizeX;
87 | pExample->windowSizeY = sizeY;
88 |
89 | /* Do not fire the callback if the initialization callback has not yet been fired. */
90 | if (pExample->hasInitBeenCalled == GL_FALSE) {
91 | return;
92 | }
93 |
94 | if (pExample->config.onSize) {
95 | pExample->config.onSize(pExample, sizeX, sizeY);
96 | }
97 | }
98 |
99 | #if defined(GLBIND_WGL)
100 | static LRESULT glbExample_DefaultWindowProcWin32(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
101 | {
102 | GLBexample* pExample = (GLBexample*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
103 | if (pExample != NULL) {
104 | switch (msg)
105 | {
106 | case WM_CLOSE:
107 | {
108 | PostQuitMessage(0);
109 | } break;
110 |
111 | case WM_SIZE:
112 | {
113 | glbExample_OnSize(pExample, LOWORD(lParam), HIWORD(lParam));
114 | }
115 |
116 | default: break;
117 | }
118 | }
119 |
120 | return DefWindowProcA(hWnd, msg, wParam, lParam);
121 | }
122 | #else
123 | static void glbExample_HandleEventX11(GLBexample* pExample, XEvent* e)
124 | {
125 | if (e->type == ClientMessage && e->xclient.data.l[0] == (long)pExample->x11.WM_DELETE_WINDOW) {
126 | XDestroyWindow(e->xclient.display, e->xclient.window);
127 | }
128 |
129 | if (e->type == ConfigureNotify) {
130 | glbExample_OnSize(pExample, e->xconfigure.width, e->xconfigure.height);
131 | }
132 | }
133 | #endif
134 |
135 | static GLenum glbExampleInitWindow(GLBexample* pExample, GLsizei sizeX, GLsizei sizeY, const char* pTitle)
136 | {
137 | if (pExample == NULL) {
138 | return GL_INVALID_VALUE;
139 | }
140 |
141 | #if defined(GLBIND_WGL)
142 | {
143 | WNDCLASSEXA wc;
144 | DWORD dwExStyle = 0;
145 | DWORD dwStyle = WS_OVERLAPPEDWINDOW;
146 |
147 | ZeroMemory(&wc, sizeof(wc));
148 | wc.cbSize = sizeof(wc);
149 | wc.cbWndExtra = sizeof(void*);
150 | wc.lpfnWndProc = (WNDPROC)glbExample_DefaultWindowProcWin32;
151 | wc.lpszClassName = "GLBIND_Example";
152 | wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(32512));
153 | wc.style = CS_OWNDC | CS_DBLCLKS;
154 | if (!RegisterClassExA(&wc)) {
155 | printf("Failed to register window class.\n");
156 | return -1;
157 | }
158 |
159 | pExample->win32.hWnd = CreateWindowExA(dwExStyle, "GLBIND_Example", pTitle, dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, sizeX, sizeY, NULL, NULL, NULL, NULL);
160 | if (pExample->win32.hWnd == NULL) {
161 | printf("Failed to create Win32 window.\n");
162 | return -1;
163 | }
164 |
165 | SetWindowLongPtrA(pExample->win32.hWnd, GWLP_USERDATA, (LONG_PTR)pExample);
166 |
167 | SetPixelFormat(GetDC(pExample->win32.hWnd), glbGetPixelFormat(), glbGetPFD());
168 | }
169 | #else
170 | {
171 | XSetWindowAttributes attr;
172 | XVisualInfo* pVisualInfo = glbGetFBVisualInfo();
173 |
174 | pExample->x11.pDisplay = glbGetDisplay();
175 | pVisualInfo = glbGetFBVisualInfo();
176 | pExample->x11.WM_DELETE_WINDOW = XInternAtom(pExample->x11.pDisplay, "WM_DELETE_WINDOW", False);
177 |
178 | attr.colormap = glbGetColormap();
179 | attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask | VisibilityChangeMask;
180 |
181 | pExample->x11.window = XCreateWindow(pExample->x11.pDisplay, XRootWindow(pExample->x11.pDisplay, pVisualInfo->screen), 0, 0, sizeX, sizeY, 0, pVisualInfo->depth, InputOutput, pVisualInfo->visual, CWColormap | CWEventMask, &attr);
182 | if (pExample->x11.window == 0) {
183 | printf("Failed to create X11 window.\n");
184 | return -1;
185 | }
186 |
187 | XSetWMProtocols(pExample->x11.pDisplay, pExample->x11.window, &pExample->x11.WM_DELETE_WINDOW, 1);
188 | XStoreName(pExample->x11.pDisplay, pExample->x11.window, pTitle);
189 | }
190 | #endif
191 |
192 | return GL_NO_ERROR;
193 | }
194 |
195 | static void glbExampleUninitWindow(GLBexample* pExample)
196 | {
197 | if (pExample == NULL) {
198 | return;
199 | }
200 |
201 | #if defined(GLBIND_WGL)
202 | DestroyWindow(pExample->win32.hWnd);
203 | #else
204 | XDestroyWindow(pExample->x11.pDisplay, pExample->x11.window);
205 | #endif
206 | }
207 |
208 | static void glbExampleShowWindowAndMakeCurrent(GLBexample* pExample)
209 | {
210 | if (pExample == NULL) {
211 | return;
212 | }
213 |
214 | #if defined(GLBIND_WGL)
215 | ShowWindow(pExample->win32.hWnd, SW_SHOWNORMAL);
216 | pExample->gl.wglMakeCurrent(GetDC(pExample->win32.hWnd), glbGetRC()); /* Using the local API to avoid the need to link to OpenGL32.dll. */
217 | #else
218 | XMapRaised(pExample->x11.pDisplay, pExample->x11.window); /* <-- Show the window. */
219 | pExample->gl.glXMakeCurrent(pExample->x11.pDisplay, pExample->x11.window, glbGetRC());
220 | #endif
221 | }
222 |
223 | GLenum glbExampleInit(GLBexample* pExample, GLBexampleconfig* pConfig)
224 | {
225 | GLenum result;
226 |
227 | if (pExample == NULL || pConfig == NULL) {
228 | return GL_INVALID_VALUE;
229 | }
230 |
231 | glbZeroObject(pExample);
232 | pExample->config = *pConfig;
233 |
234 | result = glbInit(&pExample->gl, pConfig->pGLBConfig);
235 | if (result != GL_NO_ERROR) {
236 | return result;
237 | }
238 |
239 | /* Create the window. */
240 | result = glbExampleInitWindow(pExample, pConfig->windowSizeX, pConfig->windowSizeY, (pConfig->pWindowTitle != NULL) ? pConfig->pWindowTitle : "glbind");
241 | if (result != GL_NO_ERROR) {
242 | glbUninit();
243 | return result;
244 | }
245 |
246 | /* Now show the window. */
247 | glbExampleShowWindowAndMakeCurrent(pExample);
248 |
249 | /* We need to wait for the context to be made current before calling the init callback to ensure resources can be loaded without an explicit MakeCurrent(). */
250 | result = glbExample_OnInit(pExample);
251 | if (result != GL_NO_ERROR) {
252 | glbExampleUninitWindow(pExample);
253 | glbUninit();
254 | return result;
255 | }
256 |
257 | /* Do an initial onSize call. */
258 | glbExample_OnSize(pExample, pConfig->windowSizeX, pConfig->windowSizeY);
259 |
260 | return GL_NO_ERROR;
261 | }
262 |
263 | void glbExampleUninit(GLBexample* pExample)
264 | {
265 | if (pExample == NULL) {
266 | return;
267 | }
268 |
269 | glbExampleUninitWindow(pExample);
270 | glbUninit();
271 | }
272 |
273 | int glbExampleRun(GLBexample* pExample)
274 | {
275 | #if defined(GLBIND_WGL)
276 | for (;;) {
277 | MSG msg;
278 | while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
279 | if (msg.message == WM_QUIT) {
280 | return (int)msg.wParam;
281 | }
282 |
283 | TranslateMessage(&msg);
284 | DispatchMessageA(&msg);
285 | }
286 |
287 | if (pExample->config.onDraw) {
288 | pExample->config.onDraw(pExample);
289 | }
290 |
291 | SwapBuffers(GetDC(pExample->win32.hWnd));
292 | }
293 | #else
294 | for (;;) {
295 | if (XPending(pExample->x11.pDisplay) > 0) {
296 | XEvent x11Event;
297 | XNextEvent(pExample->x11.pDisplay, &x11Event);
298 |
299 | if (x11Event.type == ClientMessage) {
300 | if ((Atom)x11Event.xclient.data.l[0] == pExample->x11.WM_DELETE_WINDOW) {
301 | return 0; /* Received a quit message. */
302 | }
303 | };
304 |
305 | glbExample_HandleEventX11(pExample, &x11Event);
306 | } else {
307 | if (pExample->config.onDraw) {
308 | pExample->config.onDraw(pExample);
309 | }
310 |
311 | pExample->gl.glXSwapBuffers(pExample->x11.pDisplay, pExample->x11.window);
312 | }
313 | }
314 | #endif
315 | }
316 |
--------------------------------------------------------------------------------
/resources/README.md:
--------------------------------------------------------------------------------
1 | OpenGL XML:
2 | https://github.com/KhronosGroup/OpenGL-Registry/blob/master/xml/gl.xml
3 | https://github.com/KhronosGroup/OpenGL-Registry/blob/master/xml/wgl.xml
4 | https://github.com/KhronosGroup/OpenGL-Registry/blob/master/xml/glx.xml
--------------------------------------------------------------------------------
/source/glbind_build.cpp:
--------------------------------------------------------------------------------
1 | #include "external/tinyxml2.cpp"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #define GLB_BUILD_XML_PATH_GL "resources/gl.xml"
9 | #define GLB_BUILD_XML_PATH_WGL "resources/wgl.xml"
10 | #define GLB_BUILD_XML_PATH_GLX "resources/glx.xml"
11 | #define GLB_BUILD_TEMPLATE_PATH "source/glbind_template.h"
12 |
13 | // Edit these if you want to blacklist specific extensions.
14 | static const char* g_BlacklistedExtensions[] = {
15 | "GLX_SGIX_dmbuffer", // Don't know what the DMparams and DMbuffer types are. I assume "DM" means "direct memory"?
16 | "GLX_SGIX_video_source" // Don't know what the VLServer, VLPath and VLNode types are.
17 | };
18 |
19 | // Edit these if you want to blacklist specific extension vendors.
20 | static const char* g_BlacklistedExtensionVendors[] = {
21 | /*"SGIX"*/
22 | ""
23 | };
24 |
25 |
26 | typedef int glbResult;
27 | #define GLB_SUCCESS 0
28 | #define GLB_ALREADY_PROCESSED 1 /* Not an error. Used to indicate that a type has already been output. */
29 | #define GLB_ERROR -1
30 | #define GLB_INVALID_ARGS -2
31 | #define GLB_OUT_OF_MEMORY -3
32 | #define GLB_FILE_TOO_BIG -4
33 | #define GLB_FAILED_TO_OPEN_FILE -5
34 | #define GLB_FAILED_TO_READ_FILE -6
35 | #define GLB_FAILED_TO_WRITE_FILE -7
36 |
37 | std::string glbLTrim(const std::string &s)
38 | {
39 | std::string result = s;
40 | result.erase(result.begin(), std::find_if(result.begin(), result.end(), [](int character) { return !std::isspace(character); }));
41 | return result;
42 | }
43 |
44 | std::string glbRTrim(const std::string &s)
45 | {
46 | std::string result = s;
47 | result.erase(std::find_if(result.rbegin(), result.rend(), [](int character) { return !std::isspace(character); }).base(), result.end());
48 | return result;
49 | }
50 |
51 | std::string glbTrim(const std::string &s)
52 | {
53 | return glbLTrim(glbRTrim(s));
54 | }
55 |
56 | std::string glbReplaceAll(const std::string &source, const std::string &from, const std::string &to)
57 | {
58 | std::string result;
59 | std::string::size_type lastPos = 0;
60 |
61 | for (;;) {
62 | std::string::size_type findPos = source.find(from, lastPos);
63 | if (findPos == std::string::npos) {
64 | break;
65 | }
66 |
67 | result.append(source, lastPos, findPos - lastPos);
68 | result.append(to);
69 | lastPos = findPos + from.length();
70 | }
71 |
72 | result.append(source.substr(lastPos));
73 | return result;
74 | }
75 |
76 | void glbReplaceAllInline(std::string &source, const std::string &from, const std::string &to)
77 | {
78 | source = glbReplaceAll(source, from, to);
79 | }
80 |
81 | std::string glbToUpper(const std::string &source)
82 | {
83 | // Quick and dirty...
84 | std::string upper;
85 | for (size_t i = 0; i < source.size(); ++i) {
86 | upper += (char)std::toupper(source[i]);
87 | }
88 | return upper;
89 | }
90 |
91 | bool glbContains(const std::string &source, const char* other)
92 | {
93 | return source.find(other) != std::string::npos;
94 | }
95 |
96 |
97 |
98 | glbResult glbFOpen(const char* filePath, const char* openMode, FILE** ppFile)
99 | {
100 | if (filePath == NULL || openMode == NULL || ppFile == NULL) {
101 | return GLB_INVALID_ARGS;
102 | }
103 |
104 | #if defined(_MSC_VER) && _MSC_VER > 1400 /* 1400 = Visual Studio 2005 */
105 | {
106 | if (fopen_s(ppFile, filePath, openMode) != 0) {
107 | return GLB_FAILED_TO_OPEN_FILE;
108 | }
109 | }
110 | #else
111 | {
112 | FILE* pFile = fopen(filePath, openMode);
113 | if (pFile == NULL) {
114 | return GLB_FAILED_TO_OPEN_FILE;
115 | }
116 |
117 | *ppFile = pFile;
118 | }
119 | #endif
120 |
121 | return GLB_SUCCESS;
122 | }
123 |
124 | glbResult glbOpenAndReadFileWithExtraData(const char* filePath, size_t* pFileSizeOut, void** ppFileData, size_t extraBytes)
125 | {
126 | glbResult result;
127 | FILE* pFile;
128 | uint64_t fileSize;
129 | void* pFileData;
130 | size_t bytesRead;
131 |
132 | /* Safety. */
133 | if (pFileSizeOut) *pFileSizeOut = 0;
134 | if (ppFileData) *ppFileData = NULL;
135 |
136 | if (filePath == NULL) {
137 | return GLB_INVALID_ARGS;
138 | }
139 |
140 | result = glbFOpen(filePath, "rb", &pFile);
141 | if (result != GLB_SUCCESS) {
142 | return GLB_FAILED_TO_OPEN_FILE;
143 | }
144 |
145 | fseek(pFile, 0, SEEK_END);
146 | fileSize = ftell(pFile);
147 | fseek(pFile, 0, SEEK_SET);
148 |
149 | if (fileSize + extraBytes > SIZE_MAX) {
150 | fclose(pFile);
151 | return GLB_FILE_TOO_BIG;
152 | }
153 |
154 | pFileData = malloc((size_t)fileSize + extraBytes); /* <-- Safe cast due to the check above. */
155 | if (pFileData == NULL) {
156 | fclose(pFile);
157 | return GLB_OUT_OF_MEMORY;
158 | }
159 |
160 | bytesRead = fread(pFileData, 1, (size_t)fileSize, pFile);
161 | if (bytesRead != fileSize) {
162 | free(pFileData);
163 | fclose(pFile);
164 | return GLB_FAILED_TO_READ_FILE;
165 | }
166 |
167 | fclose(pFile);
168 |
169 | if (pFileSizeOut) {
170 | *pFileSizeOut = (size_t)fileSize;
171 | }
172 |
173 | if (ppFileData) {
174 | *ppFileData = pFileData;
175 | } else {
176 | free(pFileData);
177 | }
178 |
179 | return GLB_SUCCESS;
180 | }
181 |
182 | glbResult glbOpenAndReadFile(const char* filePath, size_t* pFileSizeOut, void** ppFileData)
183 | {
184 | return glbOpenAndReadFileWithExtraData(filePath, pFileSizeOut, ppFileData, 0);
185 | }
186 |
187 | glbResult glbOpenAndReadTextFile(const char* filePath, size_t* pFileSizeOut, char** ppFileData)
188 | {
189 | size_t fileSize;
190 | char* pFileData;
191 | glbResult result = glbOpenAndReadFileWithExtraData(filePath, &fileSize, (void**)&pFileData, 1);
192 | if (result != GLB_SUCCESS) {
193 | return result;
194 | }
195 |
196 | pFileData[fileSize] = '\0';
197 |
198 | if (pFileSizeOut) {
199 | *pFileSizeOut = fileSize;
200 | }
201 |
202 | if (ppFileData) {
203 | *ppFileData = pFileData;
204 | } else {
205 | free(pFileData);
206 | }
207 |
208 | return GLB_SUCCESS;
209 | }
210 |
211 | glbResult glbOpenAndWriteFile(const char* filePath, const void* pData, size_t dataSize)
212 | {
213 | glbResult result;
214 | FILE* pFile;
215 |
216 | if (filePath == NULL) {
217 | return GLB_INVALID_ARGS;
218 | }
219 |
220 | result = glbFOpen(filePath, "wb", &pFile);
221 | if (result != GLB_SUCCESS) {
222 | return GLB_FAILED_TO_OPEN_FILE;
223 | }
224 |
225 | if (pData != NULL && dataSize > 0) {
226 | if (fwrite(pData, 1, dataSize, pFile) != dataSize) {
227 | fclose(pFile);
228 | return GLB_FAILED_TO_WRITE_FILE;
229 | }
230 | }
231 |
232 | fclose(pFile);
233 | return GLB_SUCCESS;
234 | }
235 |
236 | glbResult glbOpenAndWriteTextFile(const char* filePath, const char* text)
237 | {
238 | if (text == NULL) {
239 | text = "";
240 | }
241 |
242 | return glbOpenAndWriteFile(filePath, text, strlen(text));
243 | }
244 |
245 |
246 |
247 | struct glbType
248 | {
249 | std::string name; // Can be an attribute of an inner tag.
250 | std::string valueC; // The value as C code.
251 | std::string requires;
252 | };
253 |
254 | struct glbEnum
255 | {
256 | std::string name;
257 | std::string value; // Can be an empty string.
258 | std::string type;
259 | };
260 |
261 | struct glbGroup
262 | {
263 | std::string name;
264 | std::vector enums;
265 | };
266 |
267 | struct glbEnums
268 | {
269 | std::string name;
270 | std::string namespaceAttrib;
271 | std::string group;
272 | std::string vendor;
273 | std::string type;
274 | std::string start;
275 | std::string end;
276 | std::vector enums;
277 | };
278 |
279 | struct glbCommandParam
280 | {
281 | std::string type;
282 | std::string typeC;
283 | std::string name;
284 | std::string group; // Attribute.
285 | };
286 |
287 | struct glbCommand
288 | {
289 | std::string returnType;
290 | std::string returnTypeC;
291 | std::string name;
292 | std::vector params;
293 | std::string alias;
294 | };
295 |
296 | struct glbCommands
297 | {
298 | std::string namespaceAttrib;
299 | std::vector commands;
300 | };
301 |
302 | struct glbRequire
303 | {
304 | std::vector types;
305 | std::vector enums;
306 | std::vector commands;
307 | };
308 |
309 | struct glbFeature
310 | {
311 | std::string api;
312 | std::string name;
313 | std::string number;
314 | std::vector requires;
315 | };
316 |
317 | struct glbExtension
318 | {
319 | std::string name;
320 | std::string supported;
321 | std::vector requires;
322 | };
323 |
324 | struct glbBuild
325 | {
326 | std::vector types;
327 | std::vector groups;
328 | std::vector enums;
329 | std::vector commands;
330 | std::vector features;
331 | std::vector extensions;
332 |
333 | std::vector outputTypes;
334 | std::vector outputEnums;
335 | std::vector outputCommands;
336 | };
337 |
338 | glbResult glbBuildParseTypes(glbBuild &context, tinyxml2::XMLNode* pXMLElement)
339 | {
340 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
341 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
342 | if (pChildElement == NULL) {
343 | continue;
344 | }
345 |
346 | // Ignore tags.
347 | if (strcmp(pChildElement->Name(), "comment") == 0) {
348 | continue;
349 | }
350 |
351 | const char* name = pChildElement->Attribute("name");
352 | const char* requires = pChildElement->Attribute("requires");
353 |
354 | glbType type;
355 | type.name = (name != NULL) ? name : "";
356 | type.requires = (requires != NULL) ? requires : "";
357 |
358 | // The inner content of the child will contain the C code. We need to parse this by simply appending the text content together.
359 | for (tinyxml2::XMLNode* pInnerChild = pChild->FirstChild(); pInnerChild != NULL; pInnerChild = pInnerChild->NextSibling()) {
360 | tinyxml2::XMLElement* pInnerChildElement = pInnerChild->ToElement();
361 | if (pInnerChildElement != NULL) {
362 | if (strcmp(pInnerChildElement->Name(), "name") == 0) {
363 | type.name = pInnerChildElement->FirstChild()->Value();
364 | type.valueC += type.name;
365 | }
366 | if (strcmp(pInnerChildElement->Name(), "apientry") == 0) {
367 | type.valueC += "APIENTRY";
368 | }
369 | } else {
370 | type.valueC += pInnerChild->Value();
371 | }
372 | }
373 |
374 | context.types.push_back(type);
375 | }
376 |
377 | return GLB_SUCCESS;
378 | }
379 |
380 | glbResult glbBuildParseEnum(glbBuild &context, tinyxml2::XMLElement* pXMLElement, glbEnum &theEnum)
381 | {
382 | (void)context;
383 |
384 | const char* name = pXMLElement->Attribute("name");
385 | const char* value = pXMLElement->Attribute("value");
386 | const char* type = pXMLElement->Attribute("type");
387 |
388 | theEnum.name = (name != NULL) ? name : "";
389 | theEnum.value = (value != NULL) ? value : "";
390 | theEnum.type = (type != NULL) ? type : "";
391 |
392 | return GLB_SUCCESS;
393 | }
394 |
395 | glbResult glbBuildParseEnums(glbBuild &context, tinyxml2::XMLElement* pXMLElement)
396 | {
397 | const char* name = pXMLElement->Attribute("name");
398 | const char* namespaceAttrib = pXMLElement->Attribute("namespace");
399 | const char* group = pXMLElement->Attribute("group");
400 | const char* vendor = pXMLElement->Attribute("vendor");
401 | const char* type = pXMLElement->Attribute("type");
402 | const char* start = pXMLElement->Attribute("start");
403 | const char* end = pXMLElement->Attribute("end");
404 |
405 | glbEnums enums;
406 | enums.name = (name != NULL) ? name : "";
407 | enums.namespaceAttrib = (namespaceAttrib != NULL) ? namespaceAttrib : "";
408 | enums.group = (group != NULL) ? group : "";
409 | enums.vendor = (vendor != NULL) ? vendor : "";
410 | enums.type = (type != NULL) ? type : "";
411 | enums.start = (start != NULL) ? start : "";
412 | enums.end = (end != NULL) ? end : "";
413 |
414 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
415 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
416 | if (pChildElement == NULL) {
417 | continue;
418 | }
419 |
420 | // Ignore tags.
421 | if (strcmp(pChildElement->Name(), "enum") == 0) {
422 | glbEnum theEnum;
423 | glbResult result = glbBuildParseEnum(context, pChildElement, theEnum);
424 | if (result == GLB_SUCCESS) {
425 | enums.enums.push_back(theEnum);
426 | }
427 | }
428 | }
429 |
430 | context.enums.push_back(enums);
431 |
432 | return GLB_SUCCESS;
433 | }
434 |
435 | glbResult glbBuildParseGroup(glbBuild &context, tinyxml2::XMLElement* pXMLElement, glbGroup &group)
436 | {
437 | const char* name = pXMLElement->Attribute("name");
438 |
439 | group.name = (name != NULL) ? name : "";
440 |
441 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
442 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
443 | if (pChildElement == NULL) {
444 | continue;
445 | }
446 |
447 | if (strcmp(pChildElement->Name(), "enum") == 0) {
448 | glbEnum theEnum;
449 | glbResult result = glbBuildParseEnum(context, pChildElement, theEnum);
450 | if (result == GLB_SUCCESS) {
451 | group.enums.push_back(theEnum);
452 | }
453 | }
454 | }
455 |
456 | return GLB_SUCCESS;
457 | }
458 |
459 | glbResult glbBuildParseGroups(glbBuild &context, tinyxml2::XMLElement* pXMLElement)
460 | {
461 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
462 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
463 | if (pChildElement == NULL) {
464 | continue;
465 | }
466 |
467 | if (strcmp(pChildElement->Name(), "group") == 0) {
468 | glbGroup group;
469 | glbResult result = glbBuildParseGroup(context, pChildElement, group);
470 | if (result == GLB_SUCCESS) {
471 | context.groups.push_back(group);
472 | }
473 | }
474 | }
475 |
476 | return GLB_SUCCESS;
477 | }
478 |
479 | glbResult glbBuildParseTypeNamePair(tinyxml2::XMLElement* pXMLElement, std::string &type, std::string &typeC, std::string &name)
480 | {
481 | // Everything up to the name is the type. We set "type" to the value inside the or tag, if any. "typeC" will be set to the
482 | // whole type up to, but not including, the tag.
483 | type = "";
484 | typeC = "";
485 | name = "";
486 |
487 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
488 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
489 | if (pChildElement != NULL) {
490 | if (strcmp(pChildElement->Name(), "name") == 0) {
491 | name = pChildElement->FirstChild()->Value();
492 | break;
493 | } else {
494 | typeC += pChildElement->FirstChild()->Value();
495 | if (strcmp(pChildElement->Name(), "type") == 0 || strcmp(pChildElement->Name(), "ptype") == 0) {
496 | type = pChildElement->FirstChild()->Value();
497 | }
498 | }
499 | } else {
500 | typeC += pChild->Value();
501 | }
502 | }
503 |
504 | typeC = glbTrim(typeC);
505 |
506 | return GLB_SUCCESS;
507 | }
508 |
509 | glbResult glbBuildParseCommandParam(glbBuild &context, tinyxml2::XMLElement* pXMLElement, glbCommandParam ¶m)
510 | {
511 | (void)context;
512 |
513 | return glbBuildParseTypeNamePair(pXMLElement, param.type, param.typeC, param.name);
514 | }
515 |
516 | glbResult glbBuildParseCommand(glbBuild &context, tinyxml2::XMLElement* pXMLElement, glbCommand &command)
517 | {
518 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
519 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
520 | if (pChildElement == NULL) {
521 | continue;
522 | }
523 |
524 | if (strcmp(pChildElement->Name(), "proto") == 0) {
525 | glbBuildParseTypeNamePair(pChildElement, command.returnType, command.returnTypeC, command.name);
526 | }
527 |
528 | if (strcmp(pChildElement->Name(), "param") == 0) {
529 | glbCommandParam param;
530 | glbResult result = glbBuildParseCommandParam(context, pChildElement, param);
531 | if (result != GLB_SUCCESS) {
532 | return result;
533 | }
534 |
535 | command.params.push_back(param);
536 | }
537 |
538 | if (strcmp(pChildElement->Name(), "alias") == 0) {
539 | const char* alias = pChildElement->Attribute("name");
540 | command.alias = (alias != NULL) ? alias : "";
541 | }
542 | }
543 |
544 | return GLB_SUCCESS;
545 | }
546 |
547 | glbResult glbBuildParseCommands(glbBuild &context, tinyxml2::XMLElement* pXMLElement)
548 | {
549 | glbCommands commands;
550 |
551 | const char* namespaceAttrib = pXMLElement->Attribute("namespace");
552 | commands.namespaceAttrib = (namespaceAttrib != NULL) ? namespaceAttrib : "";
553 |
554 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
555 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
556 | if (pChildElement == NULL) {
557 | continue;
558 | }
559 |
560 | if (strcmp(pChildElement->Name(), "command") == 0) {
561 | glbCommand command;
562 | glbResult result = glbBuildParseCommand(context, pChildElement, command);
563 | if (result == GLB_SUCCESS) {
564 | commands.commands.push_back(command);
565 | }
566 | }
567 | }
568 |
569 | context.commands.push_back(commands);
570 |
571 | return GLB_SUCCESS;
572 | }
573 |
574 | glbResult glbBuildParseRequire(glbBuild &context, tinyxml2::XMLElement* pXMLElement, glbRequire &require)
575 | {
576 | (void)context;
577 |
578 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
579 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
580 | if (pChildElement == NULL) {
581 | continue;
582 | }
583 |
584 | if (strcmp(pChildElement->Name(), "type") == 0) {
585 | require.types.push_back(pChildElement->Attribute("name"));
586 | }
587 |
588 | if (strcmp(pChildElement->Name(), "enum") == 0) {
589 | require.enums.push_back(pChildElement->Attribute("name"));
590 | }
591 |
592 | if (strcmp(pChildElement->Name(), "command") == 0) {
593 | require.commands.push_back(pChildElement->Attribute("name"));
594 | }
595 | }
596 |
597 | return GLB_SUCCESS;
598 | }
599 |
600 | glbResult glbBuildParseFeature(glbBuild &context, tinyxml2::XMLElement* pXMLElement)
601 | {
602 | glbFeature feature;
603 |
604 | const char* api = pXMLElement->Attribute("api");
605 | const char* name = pXMLElement->Attribute("name");
606 | const char* number = pXMLElement->Attribute("number");
607 |
608 | feature.api = (api != NULL) ? api : "";
609 | feature.name = (name != NULL) ? name : "";
610 | feature.number = (number != NULL) ? number : "";
611 |
612 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
613 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
614 | if (pChildElement == NULL) {
615 | continue;
616 | }
617 |
618 | if (strcmp(pChildElement->Name(), "require") == 0) {
619 | glbRequire require;
620 | glbResult result = glbBuildParseRequire(context, pChildElement, require);
621 | if (result != GLB_SUCCESS) {
622 | return result;
623 | }
624 |
625 | feature.requires.push_back(require);
626 | }
627 | }
628 |
629 | context.features.push_back(feature);
630 |
631 | return GLB_SUCCESS;
632 | }
633 |
634 |
635 | glbResult glbBuildParseExtension(glbBuild &context, tinyxml2::XMLElement* pXMLElement, glbExtension &extension)
636 | {
637 | const char* name = pXMLElement->Attribute("name");
638 | const char* supported = pXMLElement->Attribute("supported");
639 |
640 | extension.name = (name != NULL) ? name : "";
641 | extension.supported = (supported != NULL) ? supported : "";
642 |
643 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
644 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
645 | if (pChildElement == NULL) {
646 | continue;
647 | }
648 |
649 | if (strcmp(pChildElement->Name(), "require") == 0) {
650 | glbRequire require;
651 | glbResult result = glbBuildParseRequire(context, pChildElement, require);
652 | if (result != GLB_SUCCESS) {
653 | return result;
654 | }
655 |
656 | extension.requires.push_back(require);
657 | }
658 | }
659 |
660 | return GLB_SUCCESS;
661 | }
662 |
663 | glbResult glbBuildParseExtensions(glbBuild &context, tinyxml2::XMLElement* pXMLElement)
664 | {
665 | for (tinyxml2::XMLNode* pChild = pXMLElement->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
666 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
667 | if (pChildElement == NULL) {
668 | continue;
669 | }
670 |
671 | if (strcmp(pChildElement->Name(), "extension") == 0) {
672 | glbExtension extension;
673 | glbResult result = glbBuildParseExtension(context, pChildElement, extension);
674 | if (result != GLB_SUCCESS) {
675 | return result;
676 | }
677 |
678 | context.extensions.push_back(extension);
679 | }
680 | }
681 |
682 | return GLB_SUCCESS;
683 | }
684 |
685 | glbResult glbBuildLoadXML(glbBuild &context, tinyxml2::XMLDocument &doc)
686 | {
687 | // The root node is the node.
688 | tinyxml2::XMLElement* pRoot = doc.RootElement();
689 | if (pRoot == NULL) {
690 | printf("Failed to retrieve root node.\n");
691 | return -1;
692 | }
693 |
694 | if (strcmp(pRoot->Name(), "registry") != 0) {
695 | printf("Unexpected root node. Expecting \"registry\", but got \"%s\"", pRoot->Name());
696 | return -1;
697 | }
698 |
699 | for (tinyxml2::XMLNode* pChild = pRoot->FirstChild(); pChild != NULL; pChild = pChild->NextSibling()) {
700 | tinyxml2::XMLElement* pChildElement = pChild->ToElement();
701 | if (pChildElement == NULL) {
702 | continue; // Could be a comment. In any case we don't care about anything that's not in a child node.
703 | }
704 |
705 | if (strcmp(pChildElement->Name(), "types") == 0) {
706 | glbBuildParseTypes(context, pChildElement);
707 | }
708 | if (strcmp(pChildElement->Name(), "groups") == 0) {
709 | glbBuildParseGroups(context, pChildElement);
710 | }
711 | if (strcmp(pChildElement->Name(), "enums") == 0) {
712 | glbBuildParseEnums(context, pChildElement);
713 | }
714 | if (strcmp(pChildElement->Name(), "commands") == 0) {
715 | glbBuildParseCommands(context, pChildElement);
716 | }
717 | if (strcmp(pChildElement->Name(), "feature") == 0) {
718 | glbBuildParseFeature(context, pChildElement);
719 | }
720 | if (strcmp(pChildElement->Name(), "extensions") == 0) {
721 | glbBuildParseExtensions(context, pChildElement);
722 | }
723 | }
724 |
725 | return GLB_SUCCESS;
726 | }
727 |
728 | glbResult glbBuildLoadXMLFile(glbBuild &context, const char* filePath)
729 | {
730 | tinyxml2::XMLDocument docGL;
731 | tinyxml2::XMLError xmlError = docGL.LoadFile(filePath);
732 | if (xmlError != tinyxml2::XML_SUCCESS) {
733 | printf("Failed to parse %s\n", filePath);
734 | return (int)xmlError;
735 | }
736 |
737 | return glbBuildLoadXML(context, docGL);
738 | }
739 |
740 |
741 | bool glbDoesExtensionBelongToVendor(const std::string &extensionName, const std::string &vendor)
742 | {
743 | return extensionName.find("_" + vendor + "_") != std::string::npos;
744 | }
745 |
746 | bool glbIsExtensionBlackListed(const char* extensionName)
747 | {
748 | for (auto blacklistedExtension : g_BlacklistedExtensions) {
749 | if (strcmp(blacklistedExtension, extensionName) == 0) {
750 | return true;
751 | }
752 | }
753 |
754 | for (auto vendor : g_BlacklistedExtensionVendors) {
755 | if (glbDoesExtensionBelongToVendor(extensionName, vendor)) {
756 | return true;
757 | }
758 | }
759 |
760 | return false;
761 | }
762 |
763 | bool glbBuildIsCommandIgnored(const char* commandName)
764 | {
765 | // The following commands should not be included in anything as they are not strictly OpenGL related.
766 | static const char* ignoredCommands[] = {
767 | "ChoosePixelFormat",
768 | "DescribePixelFormat",
769 | "GetEnhMetaFilePixelFormat",
770 | "GetPixelFormat",
771 | "SetPixelFormat",
772 | "SwapBuffers",
773 | "wglUseFontBitmaps",
774 | "wglUseFontOutlines",
775 | };
776 |
777 | for (size_t i = 0; i < sizeof(ignoredCommands)/sizeof(ignoredCommands[0]); ++i) {
778 | if (strcmp(ignoredCommands[i], commandName) == 0) {
779 | return true;
780 | }
781 | }
782 |
783 | return false;
784 | }
785 |
786 |
787 | bool glbBuildHasTypeBeenOutput(glbBuild &context, const char* typeName)
788 | {
789 | for (size_t iType = 0; iType < context.outputTypes.size(); ++iType) {
790 | if (context.outputTypes[iType] == typeName) {
791 | return true;
792 | }
793 | }
794 |
795 | return false; /* Not found. */
796 | }
797 |
798 | bool glbBuildHasCommandBeenOutput(glbBuild &context, const char* commandName)
799 | {
800 | for (size_t iCommand = 0; iCommand < context.outputCommands.size(); ++iCommand) {
801 | if (context.outputCommands[iCommand] == commandName) {
802 | return true;
803 | }
804 | }
805 |
806 | return false; /* Not found. */
807 | }
808 |
809 | glbResult glbBuildFindType(glbBuild &context, const char* typeName, glbType** ppType)
810 | {
811 | *ppType = NULL;
812 |
813 | for (size_t iType = 0; iType < context.types.size(); ++iType) {
814 | if (context.types[iType].name == typeName) {
815 | *ppType = &context.types[iType];
816 | return GLB_SUCCESS;
817 | }
818 | }
819 |
820 | return GLB_ERROR;
821 | }
822 |
823 | glbResult glbBuildFindEnum(glbBuild &context, const char* enumName, glbEnum** ppEnum)
824 | {
825 | *ppEnum = NULL;
826 |
827 | for (size_t iEnums = 0; iEnums < context.enums.size(); ++iEnums) {
828 | glbEnums &enums = context.enums[iEnums];
829 | for (size_t iEnum = 0; iEnum < enums.enums.size(); ++iEnum) {
830 | if (context.enums[iEnums].enums[iEnum].name == enumName) {
831 | *ppEnum = &context.enums[iEnums].enums[iEnum];
832 | return GLB_SUCCESS;
833 | }
834 | }
835 | }
836 |
837 | return GLB_ERROR;
838 | }
839 |
840 | glbResult glbBuildFindCommand(glbBuild &context, const char* commandName, glbCommand** ppCommand)
841 | {
842 | *ppCommand = NULL;
843 |
844 | for (size_t iCommands = 0; iCommands < context.commands.size(); ++iCommands) {
845 | glbCommands &commands = context.commands[iCommands];
846 | for (size_t iCommand = 0; iCommand < commands.commands.size(); ++iCommand) {
847 | if (context.commands[iCommands].commands[iCommand].name == commandName) {
848 | *ppCommand = &context.commands[iCommands].commands[iCommand];
849 | return GLB_SUCCESS;
850 | }
851 | }
852 | }
853 |
854 | return GLB_ERROR;
855 | }
856 |
857 |
858 | glbResult glbBuildGenerateCode_C_Main_Type(glbBuild &context, const char* typeName, std::string &codeOut)
859 | {
860 | // Special case for khrplatform. We don't want to include this because we don't use khrplatform.h. Just pretend it's already been output.
861 | if (strcmp(typeName, "khrplatform") == 0) {
862 | return GLB_ALREADY_PROCESSED;
863 | }
864 |
865 | // We only output the type if it hasn't already been output.
866 | if (!glbBuildHasTypeBeenOutput(context, typeName)) {
867 | glbType* pType;
868 | glbResult result = glbBuildFindType(context, typeName, &pType);
869 | if (result != GLB_SUCCESS) {
870 | return result;
871 | }
872 |
873 | if (pType->valueC != "") {
874 | codeOut += pType->valueC + "\n";
875 | }
876 |
877 | context.outputTypes.push_back(typeName);
878 | }
879 |
880 | return GLB_SUCCESS;
881 | }
882 |
883 | glbResult glbBuildGenerateCode_C_Main_RequireTypes(glbBuild &context, glbRequire &require, std::string &codeOut)
884 | {
885 | glbResult result;
886 |
887 | // Standalone types.
888 | for (size_t iType = 0; iType < require.types.size(); ++iType) {
889 | result = glbBuildGenerateCode_C_Main_Type(context, require.types[iType].c_str(), codeOut);
890 | if (result != GLB_SUCCESS && result != GLB_ALREADY_PROCESSED) {
891 | return result;
892 | }
893 | }
894 |
895 | // Required types.
896 | for (size_t iCommand = 0; iCommand < require.commands.size(); ++iCommand) {
897 | glbCommand* pCommand;
898 | result = glbBuildFindCommand(context, require.commands[iCommand].c_str(), &pCommand);
899 | if (result != GLB_SUCCESS) {
900 | return result;
901 | }
902 |
903 | if (pCommand->returnType != "") {
904 | glbBuildGenerateCode_C_Main_Type(context, pCommand->returnType.c_str(), codeOut);
905 | }
906 |
907 | for (size_t iParam = 0; iParam < pCommand->params.size(); ++iParam) {
908 | glbCommandParam ¶m = pCommand->params[iParam];
909 | if (param.type != "") {
910 | glbBuildGenerateCode_C_Main_Type(context, param.type.c_str(), codeOut);
911 | }
912 | }
913 | }
914 |
915 | return GLB_SUCCESS;
916 | }
917 |
918 | glbResult glbBuildGenerateCode_C_Main_RequireEnums(glbBuild &context, glbRequire &require, std::string &codeOut)
919 | {
920 | glbResult result;
921 |
922 | for (size_t iEnum = 0; iEnum < require.enums.size(); ++iEnum) {
923 | glbEnum* pEnum;
924 | result = glbBuildFindEnum(context, require.enums[iEnum].c_str(), &pEnum);
925 | if (result != GLB_SUCCESS) {
926 | return result;
927 | }
928 |
929 | codeOut += "#define " + pEnum->name + " " + pEnum->value + "\n";
930 | }
931 |
932 | return GLB_SUCCESS;
933 | }
934 |
935 | glbResult glbBuildGenerateCode_C_Main_RequireCommands(glbBuild &context, glbRequire &require, std::string &codeOut)
936 | {
937 | glbResult result;
938 |
939 | for (size_t iCommand = 0; iCommand < require.commands.size(); ++iCommand) {
940 | const char* commandName = require.commands[iCommand].c_str();
941 | if (!glbBuildHasCommandBeenOutput(context, commandName)) {
942 | glbCommand* pCommand;
943 | result = glbBuildFindCommand(context, require.commands[iCommand].c_str(), &pCommand);
944 | if (result != GLB_SUCCESS) {
945 | return result;
946 | }
947 |
948 | codeOut += "typedef " + pCommand->returnTypeC + " (APIENTRYP PFN" + glbToUpper(pCommand->name) + "PROC)(";
949 | if (pCommand->params.size() > 0) {
950 | for (size_t iParam = 0; iParam < pCommand->params.size(); ++iParam) {
951 | if (iParam != 0) {
952 | codeOut += ", ";
953 | }
954 | codeOut += pCommand->params[iParam].typeC + " " + pCommand->params[iParam].name;
955 | }
956 | } else {
957 | codeOut += "void"; // we need to use "func(void)" syntax for compatibility with older versions of C.
958 | }
959 | codeOut += ");\n";
960 |
961 | context.outputCommands.push_back(commandName);
962 | }
963 | }
964 |
965 | return GLB_SUCCESS;
966 | }
967 |
968 |
969 | glbResult glbBuildGenerateCode_C_Main_Feature(glbBuild &context, glbFeature &feature, std::string &codeOut)
970 | {
971 | codeOut += "#ifndef " + feature.name + "\n";
972 | codeOut += "#define " + feature.name + " 1\n";
973 | {
974 | // Types.
975 | for (size_t iRequire = 0; iRequire < feature.requires.size(); ++iRequire) {
976 | glbResult result = glbBuildGenerateCode_C_Main_RequireTypes(context, feature.requires[iRequire], codeOut);
977 | if (result != GLB_SUCCESS) {
978 | return result;
979 | }
980 | }
981 |
982 | // Enums.
983 | for (size_t iRequire = 0; iRequire < feature.requires.size(); ++iRequire) {
984 | glbResult result = glbBuildGenerateCode_C_Main_RequireEnums(context, feature.requires[iRequire], codeOut);
985 | if (result != GLB_SUCCESS) {
986 | return result;
987 | }
988 | }
989 |
990 | // Commands.
991 | for (size_t iRequire = 0; iRequire < feature.requires.size(); ++iRequire) {
992 | glbResult result = glbBuildGenerateCode_C_Main_RequireCommands(context, feature.requires[iRequire], codeOut);
993 | if (result != GLB_SUCCESS) {
994 | return result;
995 | }
996 | }
997 | }
998 | codeOut += "#endif /* " + feature.name + " */\n";
999 |
1000 | return GLB_SUCCESS;
1001 | }
1002 |
1003 | glbResult glbBuildGenerateCode_C_Main_FeaturesByAPI(glbBuild &context, const char* api, std::string &codeOut)
1004 | {
1005 | int counter = 0; // Only used for knowing whether or not a new line should be added.
1006 |
1007 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1008 | glbFeature &feature = context.features[iFeature];
1009 | if (feature.api == api) {
1010 | if (counter > 0) {
1011 | codeOut += "\n";
1012 | }
1013 |
1014 | glbResult result = glbBuildGenerateCode_C_Main_Feature(context, feature, codeOut);
1015 | if (result != GLB_SUCCESS) {
1016 | return result;
1017 | }
1018 |
1019 | counter += 1;
1020 | }
1021 | }
1022 |
1023 | return GLB_SUCCESS;
1024 | }
1025 |
1026 | glbResult glbBuildGenerateCode_C_Main_Extension(glbBuild &context, glbExtension &extension, std::string &codeOut)
1027 | {
1028 | codeOut += "#ifndef " + extension.name + "\n";
1029 | codeOut += "#define " + extension.name + " 1\n";
1030 | {
1031 | // Types.
1032 | for (size_t iRequire = 0; iRequire < extension.requires.size(); ++iRequire) {
1033 | glbResult result = glbBuildGenerateCode_C_Main_RequireTypes(context, extension.requires[iRequire], codeOut);
1034 | if (result != GLB_SUCCESS) {
1035 | return result;
1036 | }
1037 | }
1038 |
1039 | // Enums.
1040 | for (size_t iRequire = 0; iRequire < extension.requires.size(); ++iRequire) {
1041 | glbResult result = glbBuildGenerateCode_C_Main_RequireEnums(context, extension.requires[iRequire], codeOut);
1042 | if (result != GLB_SUCCESS) {
1043 | return result;
1044 | }
1045 | }
1046 |
1047 | // Commands.
1048 | for (size_t iRequire = 0; iRequire < extension.requires.size(); ++iRequire) {
1049 | glbResult result = glbBuildGenerateCode_C_Main_RequireCommands(context, extension.requires[iRequire], codeOut);
1050 | if (result != GLB_SUCCESS) {
1051 | return result;
1052 | }
1053 | }
1054 | }
1055 | codeOut += "#endif /* " + extension.name + " */\n";
1056 |
1057 | return GLB_SUCCESS;
1058 | }
1059 |
1060 | glbResult glbBuildGenerateCode_C_Main(glbBuild &context, std::string &codeOut)
1061 | {
1062 | glbResult result;
1063 | int counter; // Used for tracking whether or not new lines need to be added.
1064 |
1065 | // Feature order is the following.
1066 | // - gl
1067 | // - wgl
1068 | // - glx
1069 | result = glbBuildGenerateCode_C_Main_FeaturesByAPI(context, "gl", codeOut);
1070 | if (result != GLB_SUCCESS) {
1071 | return result;
1072 | }
1073 |
1074 | codeOut += "\n#if defined(GLBIND_WGL)\n";
1075 | result = glbBuildGenerateCode_C_Main_FeaturesByAPI(context, "wgl", codeOut);
1076 | if (result != GLB_SUCCESS) {
1077 | return result;
1078 | }
1079 | codeOut += "#endif /* GLBIND_WGL */\n";
1080 |
1081 | codeOut += "\n#if defined(GLBIND_GLX)\n";
1082 | result = glbBuildGenerateCode_C_Main_FeaturesByAPI(context, "glx", codeOut);
1083 | if (result != GLB_SUCCESS) {
1084 | return result;
1085 | }
1086 | codeOut += "#endif /* GLBIND_GLX */\n";
1087 |
1088 | // TODO: All other APIs no in gl, wgl and glx (gles2, etc.)?
1089 |
1090 |
1091 | // Now we need to do extensions. For cleanliness we want to group extensions. We do gl/glcore first, then wgl, then glx.
1092 | counter = 0;
1093 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1094 | glbExtension &extension = context.extensions[iExtension];
1095 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && (extension.supported == "gl" || glbContains(extension.supported, "gl|") || glbContains(extension.supported, "glcore"))) {
1096 | if (counter > 0) {
1097 | codeOut += "\n";
1098 | }
1099 | counter += 1;
1100 |
1101 | result = glbBuildGenerateCode_C_Main_Extension(context, extension, codeOut);
1102 | if (result != GLB_SUCCESS) {
1103 | return result;
1104 | }
1105 | }
1106 | }
1107 |
1108 | // WGL extensions.
1109 | codeOut += "\n#if defined(GLBIND_WGL)\n";
1110 | counter = 0;
1111 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1112 | glbExtension &extension = context.extensions[iExtension];
1113 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "wgl")) {
1114 | if (counter > 0) {
1115 | codeOut += "\n";
1116 | }
1117 | counter += 1;
1118 |
1119 | result = glbBuildGenerateCode_C_Main_Extension(context, extension, codeOut);
1120 | if (result != GLB_SUCCESS) {
1121 | return result;
1122 | }
1123 | }
1124 | }
1125 | codeOut += "#endif /* GLBIND_WGL */\n";
1126 |
1127 | // GLX extensions.
1128 | codeOut += "\n#if defined(GLBIND_GLX)\n";
1129 | counter = 0;
1130 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1131 | glbExtension &extension = context.extensions[iExtension];
1132 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "glx")) {
1133 | if (counter > 0) {
1134 | codeOut += "\n";
1135 | }
1136 | counter += 1;
1137 |
1138 | result = glbBuildGenerateCode_C_Main_Extension(context, extension, codeOut);
1139 | if (result != GLB_SUCCESS) {
1140 | return result;
1141 | }
1142 | }
1143 | }
1144 | codeOut += "#endif /* GLBIND_GLX */\n";
1145 |
1146 | return GLB_SUCCESS;
1147 | }
1148 |
1149 |
1150 |
1151 | glbResult glbBuildGenerateCode_C_FuncPointersDeclGlobal_RequireCommands(glbBuild &context, int indentation, const glbRequire &require, std::vector &processedCommands, std::string &codeOut)
1152 | {
1153 | glbResult result;
1154 |
1155 | for (size_t iCommand = 0; iCommand < require.commands.size(); ++iCommand) {
1156 | std::string commandName = require.commands[iCommand];
1157 | if (!glbBuildIsCommandIgnored(commandName.c_str()) && std::find(processedCommands.begin(), processedCommands.end(), commandName) == processedCommands.end()) {
1158 | glbCommand* pCommand;
1159 | result = glbBuildFindCommand(context, require.commands[iCommand].c_str(), &pCommand);
1160 | if (result != GLB_SUCCESS) {
1161 | return result;
1162 | }
1163 |
1164 | for (int i = 0; i < indentation; ++i) {
1165 | codeOut += " ";
1166 | }
1167 | codeOut += "PFN" + glbToUpper(pCommand->name) + "PROC " + pCommand->name + ";\n";
1168 |
1169 | processedCommands.push_back(commandName);
1170 | }
1171 | }
1172 |
1173 | return GLB_SUCCESS;
1174 | }
1175 |
1176 | glbResult glbBuildGenerateCode_C_FuncPointersDeclGlobal_Extension(glbBuild &context, int indentation, const glbExtension &extension, std::vector &processedCommands, std::string &codeOut)
1177 | {
1178 | for (size_t iRequire = 0; iRequire < extension.requires.size(); ++iRequire) {
1179 | glbResult result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_RequireCommands(context, indentation, extension.requires[iRequire], processedCommands, codeOut);
1180 | if (result != GLB_SUCCESS) {
1181 | return result;
1182 | }
1183 | }
1184 |
1185 | return GLB_SUCCESS;
1186 | }
1187 |
1188 | glbResult glbBuildGenerateCode_C_FuncPointersDeclGlobal_Feature(glbBuild &context, int indentation, const glbFeature &feature, std::vector &processedCommands, std::string &codeOut)
1189 | {
1190 | for (size_t iRequire = 0; iRequire < feature.requires.size(); ++iRequire) {
1191 | glbResult result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_RequireCommands(context, indentation, feature.requires[iRequire], processedCommands, codeOut);
1192 | if (result != GLB_SUCCESS) {
1193 | return result;
1194 | }
1195 | }
1196 |
1197 | return GLB_SUCCESS;
1198 | }
1199 |
1200 | glbResult glbBuildGenerateCode_C_FuncPointersDeclGlobal(glbBuild &context, int indentation, std::string &codeOut)
1201 | {
1202 | glbResult result;
1203 | std::vector processedCommands;
1204 | bool isGlobalScope = (indentation == 0); // If the indentation is 0 it means we're generating the global symbols. Bit of a hack, but it works.
1205 |
1206 | // GL features.
1207 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1208 | glbFeature &feature = context.features[iFeature];
1209 | if (feature.api == "gl") {
1210 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_Feature(context, indentation, context.features[iFeature], processedCommands, codeOut);
1211 | if (result != GLB_SUCCESS) {
1212 | return result;
1213 | }
1214 | }
1215 | }
1216 |
1217 | // NOTE: Some headers define their own symbols for some APIs, such as the common WGL functions (wglCreateContext, etc.). This causes compiler errors
1218 | // so I'm working around this by simply not outputting them to global scope. We do, however, need these to be included in the GLBapi structure.
1219 |
1220 | // WGL features.
1221 | if (!isGlobalScope) {
1222 | codeOut += "#if defined(GLBIND_WGL)\n";
1223 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1224 | glbFeature &feature = context.features[iFeature];
1225 | if (feature.api == "wgl") {
1226 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_Feature(context, indentation, context.features[iFeature], processedCommands, codeOut);
1227 | if (result != GLB_SUCCESS) {
1228 | return result;
1229 | }
1230 | }
1231 | }
1232 | codeOut += "#endif /* GLBIND_WGL */\n";
1233 | }
1234 |
1235 | codeOut += "#if defined(GLBIND_GLX)\n";
1236 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1237 | glbFeature &feature = context.features[iFeature];
1238 | if (feature.api == "glx") {
1239 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_Feature(context, indentation, context.features[iFeature], processedCommands, codeOut);
1240 | if (result != GLB_SUCCESS) {
1241 | return result;
1242 | }
1243 | }
1244 | }
1245 | codeOut += "#endif /* GLBIND_GLX */\n";
1246 |
1247 | // GL extensions.
1248 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1249 | glbExtension &extension = context.extensions[iExtension];
1250 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && (extension.supported == "gl" || glbContains(extension.supported, "gl|") || glbContains(extension.supported, "glcore"))) {
1251 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_Extension(context, indentation, extension, processedCommands, codeOut);
1252 | if (result != GLB_SUCCESS) {
1253 | return result;
1254 | }
1255 | }
1256 | }
1257 |
1258 | // WGL extensions.
1259 | codeOut += "#if defined(GLBIND_WGL)\n";
1260 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1261 | glbExtension &extension = context.extensions[iExtension];
1262 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "wgl")) {
1263 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_Extension(context, indentation, extension, processedCommands, codeOut);
1264 | if (result != GLB_SUCCESS) {
1265 | return result;
1266 | }
1267 | }
1268 | }
1269 | codeOut += "#endif /* GLBIND_WGL */\n";
1270 |
1271 | // GLX extensions.
1272 | codeOut += "#if defined(GLBIND_GLX)\n";
1273 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1274 | glbExtension &extension = context.extensions[iExtension];
1275 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "glx")) {
1276 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal_Extension(context, indentation, extension, processedCommands, codeOut);
1277 | if (result != GLB_SUCCESS) {
1278 | return result;
1279 | }
1280 | }
1281 | }
1282 | codeOut += "#endif /* GLBIND_GLX */";
1283 |
1284 | return GLB_SUCCESS;
1285 | }
1286 |
1287 |
1288 | glbResult glbBuildGenerateCode_C_InitCurrentContextAPI_RequireCommands(glbBuild &context, const glbRequire &require, std::vector &processedCommands, std::string &codeOut)
1289 | {
1290 | glbResult result;
1291 |
1292 | for (size_t iCommand = 0; iCommand < require.commands.size(); ++iCommand) {
1293 | std::string commandName = require.commands[iCommand];
1294 | if (!glbBuildIsCommandIgnored(commandName.c_str()) && std::find(processedCommands.begin(), processedCommands.end(), commandName) == processedCommands.end()) {
1295 | glbCommand* pCommand;
1296 | result = glbBuildFindCommand(context, require.commands[iCommand].c_str(), &pCommand);
1297 | if (result != GLB_SUCCESS) {
1298 | return result;
1299 | }
1300 |
1301 | codeOut += " pAPI->" + pCommand->name + " = (PFN" + glbToUpper(pCommand->name) + "PROC)glbGetProcAddress(\"" + pCommand->name + "\");\n";
1302 |
1303 | processedCommands.push_back(commandName);
1304 | }
1305 | }
1306 |
1307 | return GLB_SUCCESS;
1308 | }
1309 |
1310 | glbResult glbBuildGenerateCode_C_InitCurrentContextAPI_Feature(glbBuild &context, const glbFeature &feature, std::vector &processedCommands, std::string &codeOut)
1311 | {
1312 | for (size_t iRequire = 0; iRequire < feature.requires.size(); ++iRequire) {
1313 | glbResult result = glbBuildGenerateCode_C_InitCurrentContextAPI_RequireCommands(context, feature.requires[iRequire], processedCommands, codeOut);
1314 | if (result != GLB_SUCCESS) {
1315 | return result;
1316 | }
1317 | }
1318 |
1319 | return GLB_SUCCESS;
1320 | }
1321 |
1322 | glbResult glbBuildGenerateCode_C_InitCurrentContextAPI_Extension(glbBuild &context, const glbExtension &extension, std::vector &processedCommands, std::string &codeOut)
1323 | {
1324 | for (size_t iRequire = 0; iRequire < extension.requires.size(); ++iRequire) {
1325 | glbResult result = glbBuildGenerateCode_C_InitCurrentContextAPI_RequireCommands(context, extension.requires[iRequire], processedCommands, codeOut);
1326 | if (result != GLB_SUCCESS) {
1327 | return result;
1328 | }
1329 | }
1330 |
1331 | return GLB_SUCCESS;
1332 | }
1333 |
1334 | glbResult glbBuildGenerateCode_C_InitCurrentContextAPI(glbBuild &context, std::string &codeOut)
1335 | {
1336 | glbResult result;
1337 | std::vector processedCommands;
1338 |
1339 | // GL features.
1340 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1341 | glbFeature &feature = context.features[iFeature];
1342 | if (feature.api == "gl") {
1343 | result = glbBuildGenerateCode_C_InitCurrentContextAPI_Feature(context, context.features[iFeature], processedCommands, codeOut);
1344 | if (result != GLB_SUCCESS) {
1345 | return result;
1346 | }
1347 | }
1348 | }
1349 |
1350 | // WGL features.
1351 | codeOut += "#if defined(GLBIND_WGL)\n";
1352 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1353 | glbFeature &feature = context.features[iFeature];
1354 | if (feature.api == "wgl") {
1355 | result = glbBuildGenerateCode_C_InitCurrentContextAPI_Feature(context, context.features[iFeature], processedCommands, codeOut);
1356 | if (result != GLB_SUCCESS) {
1357 | return result;
1358 | }
1359 | }
1360 | }
1361 | codeOut += "#endif /* GLBIND_WGL */\n";
1362 |
1363 | // GLX features.
1364 | codeOut += "#if defined(GLBIND_GLX)\n";
1365 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1366 | glbFeature &feature = context.features[iFeature];
1367 | if (feature.api == "glx") {
1368 | result = glbBuildGenerateCode_C_InitCurrentContextAPI_Feature(context, context.features[iFeature], processedCommands, codeOut);
1369 | if (result != GLB_SUCCESS) {
1370 | return result;
1371 | }
1372 | }
1373 | }
1374 | codeOut += "#endif /* GLBIND_GLX */\n";
1375 |
1376 |
1377 | // GL extensions.
1378 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1379 | glbExtension &extension = context.extensions[iExtension];
1380 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && (extension.supported == "gl" || glbContains(extension.supported, "gl|") || glbContains(extension.supported, "glcore"))) {
1381 | result = glbBuildGenerateCode_C_InitCurrentContextAPI_Extension(context, extension, processedCommands, codeOut);
1382 | if (result != GLB_SUCCESS) {
1383 | return result;
1384 | }
1385 | }
1386 | }
1387 |
1388 | // WGL extensions.
1389 | codeOut += "#if defined(GLBIND_WGL)\n";
1390 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1391 | glbExtension &extension = context.extensions[iExtension];
1392 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "wgl")) {
1393 | result = glbBuildGenerateCode_C_InitCurrentContextAPI_Extension(context, extension, processedCommands, codeOut);
1394 | if (result != GLB_SUCCESS) {
1395 | return result;
1396 | }
1397 | }
1398 | }
1399 | codeOut += "#endif /* GLBIND_WGL */\n";
1400 |
1401 | // GLX extensions.
1402 | codeOut += "#if defined(GLBIND_GLX)\n";
1403 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1404 | glbExtension &extension = context.extensions[iExtension];
1405 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "glx")) {
1406 | result = glbBuildGenerateCode_C_InitCurrentContextAPI_Extension(context, extension, processedCommands, codeOut);
1407 | if (result != GLB_SUCCESS) {
1408 | return result;
1409 | }
1410 | }
1411 | }
1412 | codeOut += "#endif /* GLBIND_GLX */";
1413 |
1414 | return GLB_SUCCESS;
1415 | }
1416 |
1417 |
1418 | glbResult glbBuildGenerateCode_C_SetGlobalAPIFromStruct_RequireCommands(glbBuild &context, const glbRequire &require, std::vector &processedCommands, std::string &codeOut)
1419 | {
1420 | glbResult result;
1421 |
1422 | for (size_t iCommand = 0; iCommand < require.commands.size(); ++iCommand) {
1423 | std::string commandName = require.commands[iCommand];
1424 | if (!glbBuildIsCommandIgnored(commandName.c_str()) && std::find(processedCommands.begin(), processedCommands.end(), commandName) == processedCommands.end()) {
1425 | glbCommand* pCommand;
1426 | result = glbBuildFindCommand(context, require.commands[iCommand].c_str(), &pCommand);
1427 | if (result != GLB_SUCCESS) {
1428 | return result;
1429 | }
1430 |
1431 | codeOut += " " + pCommand->name + " = pAPI->" + pCommand->name + ";\n";
1432 |
1433 | processedCommands.push_back(commandName);
1434 | }
1435 | }
1436 |
1437 | return GLB_SUCCESS;
1438 | }
1439 |
1440 | glbResult glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Feature(glbBuild &context, const glbFeature &feature, std::vector &processedCommands, std::string &codeOut)
1441 | {
1442 | for (size_t iRequire = 0; iRequire < feature.requires.size(); ++iRequire) {
1443 | glbResult result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_RequireCommands(context, feature.requires[iRequire], processedCommands, codeOut);
1444 | if (result != GLB_SUCCESS) {
1445 | return result;
1446 | }
1447 | }
1448 |
1449 | return GLB_SUCCESS;
1450 | }
1451 |
1452 | glbResult glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Extension(glbBuild &context, const glbExtension &extension, std::vector &processedCommands, std::string &codeOut)
1453 | {
1454 | for (size_t iRequire = 0; iRequire < extension.requires.size(); ++iRequire) {
1455 | glbResult result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_RequireCommands(context, extension.requires[iRequire], processedCommands, codeOut);
1456 | if (result != GLB_SUCCESS) {
1457 | return result;
1458 | }
1459 | }
1460 |
1461 | return GLB_SUCCESS;
1462 | }
1463 |
1464 | glbResult glbBuildGenerateCode_C_SetGlobalAPIFromStruct(glbBuild &context, std::string &codeOut)
1465 | {
1466 | glbResult result;
1467 | std::vector processedCommands;
1468 |
1469 | // GL features.
1470 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1471 | glbFeature &feature = context.features[iFeature];
1472 | if (feature.api == "gl") {
1473 | result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Feature(context, context.features[iFeature], processedCommands, codeOut);
1474 | if (result != GLB_SUCCESS) {
1475 | return result;
1476 | }
1477 | }
1478 | }
1479 |
1480 | // WGL features.
1481 |
1482 | // GLX features.
1483 | codeOut += "#if defined(GLBIND_GLX)\n";
1484 | for (size_t iFeature = 0; iFeature < context.features.size(); ++iFeature) {
1485 | glbFeature &feature = context.features[iFeature];
1486 | if (feature.api == "glx") {
1487 | result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Feature(context, context.features[iFeature], processedCommands, codeOut);
1488 | if (result != GLB_SUCCESS) {
1489 | return result;
1490 | }
1491 | }
1492 | }
1493 | codeOut += "#endif /* GLBIND_GLX */\n";
1494 |
1495 |
1496 | // GL extensions.
1497 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1498 | glbExtension &extension = context.extensions[iExtension];
1499 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && (extension.supported == "gl" || glbContains(extension.supported, "gl|") || glbContains(extension.supported, "glcore"))) {
1500 | result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Extension(context, extension, processedCommands, codeOut);
1501 | if (result != GLB_SUCCESS) {
1502 | return result;
1503 | }
1504 | }
1505 | }
1506 |
1507 | // WGL extensions.
1508 | codeOut += "#if defined(GLBIND_WGL)\n";
1509 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1510 | glbExtension &extension = context.extensions[iExtension];
1511 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "wgl")) {
1512 | result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Extension(context, extension, processedCommands, codeOut);
1513 | if (result != GLB_SUCCESS) {
1514 | return result;
1515 | }
1516 | }
1517 | }
1518 | codeOut += "#endif /* GLBIND_WGL */\n";
1519 |
1520 | // GLX extensions.
1521 | codeOut += "#if defined(GLBIND_GLX)\n";
1522 | for (size_t iExtension = 0; iExtension < context.extensions.size(); ++iExtension) {
1523 | glbExtension &extension = context.extensions[iExtension];
1524 | if (!glbIsExtensionBlackListed(extension.name.c_str()) && glbContains(extension.supported, "glx")) {
1525 | result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct_Extension(context, extension, processedCommands, codeOut);
1526 | if (result != GLB_SUCCESS) {
1527 | return result;
1528 | }
1529 | }
1530 | }
1531 | codeOut += "#endif /* GLBIND_GLX */";
1532 |
1533 | return GLB_SUCCESS;
1534 | }
1535 |
1536 | #include
1537 | glbResult glbBuildGenerateCode_C_Date(glbBuild &context, std::string &codeOut)
1538 | {
1539 | (void)context;
1540 |
1541 | time_t t = time(NULL);
1542 |
1543 | char dateStr[32];
1544 | #if defined(_MSC_VER)
1545 | struct tm local;
1546 | localtime_s(&local, &t);
1547 | strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", &local);
1548 | #else
1549 | struct tm *local = localtime(&t);
1550 | strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", local);
1551 | #endif
1552 |
1553 | codeOut += dateStr;
1554 | return GLB_SUCCESS;
1555 | }
1556 |
1557 | glbResult glbBuildGetOpenGLVersion(glbBuild &context, std::string &versionOut)
1558 | {
1559 | // The version can be retrieved from the last "gl" feature section.
1560 | std::string versionStr;
1561 | for (auto feature : context.features) {
1562 | if (feature.api == "gl") {
1563 | versionStr = feature.number;
1564 | }
1565 | }
1566 |
1567 | versionOut = versionStr;
1568 |
1569 | return GLB_SUCCESS;
1570 | }
1571 |
1572 | glbResult vkbBuildGenerateCode_C_OpenGLVersion(glbBuild &context, std::string &codeOut)
1573 | {
1574 | std::string version;
1575 | glbResult result = glbBuildGetOpenGLVersion(context, version);
1576 | if (result != GLB_SUCCESS) {
1577 | return result;
1578 | }
1579 |
1580 | codeOut += version;
1581 |
1582 | return GLB_SUCCESS;
1583 | }
1584 |
1585 | glbResult glbBuildGenerateCode_C_Revision(glbBuild &context, std::string &codeOut)
1586 | {
1587 | // Rules for the revision number:
1588 | // 1) If the OpenGL version has changed, reset the revision to 0, otherwise increment by 1.
1589 | // 2) If glbind.h cannot be found, set to 0.
1590 | std::string revision;
1591 |
1592 | size_t fileSize;
1593 | char* pFileData;
1594 | if (glbOpenAndReadTextFile("glbind.h", &fileSize, &pFileData) == GLB_SUCCESS) {
1595 | // We need to parse the previous version.
1596 | std::string prevVersionMajor;
1597 | std::string prevVersionMinor;
1598 | std::string prevVersionRevision;
1599 | const char* versionBeg = strstr((const char*)pFileData, "glbind - v");
1600 | if (versionBeg != NULL) {
1601 | versionBeg += strlen("glbind - v");
1602 |
1603 | std::string currentOpenGLVersion;
1604 | glbResult result = glbBuildGetOpenGLVersion(context, currentOpenGLVersion);
1605 | if (result != GLB_SUCCESS) {
1606 | return result;
1607 | }
1608 |
1609 | const char* cursorBeg = versionBeg;
1610 | const char* cursorEnd = versionBeg;
1611 |
1612 | cursorEnd = strstr(cursorBeg, ".");
1613 | prevVersionMajor = std::string(cursorBeg, cursorEnd-cursorBeg);
1614 | cursorBeg = cursorEnd + 1;
1615 |
1616 | cursorEnd = strstr(cursorBeg, ".");
1617 | prevVersionMinor = std::string(cursorBeg, cursorEnd-cursorBeg);
1618 | cursorBeg = cursorEnd + 1;
1619 |
1620 | cursorEnd = strstr(cursorBeg, " ");
1621 | prevVersionRevision = std::string(cursorBeg, cursorEnd-cursorBeg);
1622 | cursorBeg = cursorEnd + 1;
1623 |
1624 | std::string previousOpenGLVersion = prevVersionMajor + "." + prevVersionMinor;
1625 | if (currentOpenGLVersion == previousOpenGLVersion) {
1626 | // OpenGL versions are the same, so increment.
1627 | revision = std::to_string(atoi(prevVersionRevision.c_str()) + 1);
1628 | } else {
1629 | // OpenGL versions are different, so reset.
1630 | revision = "0";
1631 | }
1632 | } else {
1633 | // Couldn't find the previous version.
1634 | revision = "0";
1635 | }
1636 | } else {
1637 | // vkbind.h was not found.
1638 | revision = "0";
1639 | }
1640 |
1641 | codeOut += revision;
1642 | return GLB_SUCCESS;
1643 | }
1644 |
1645 | glbResult glbBuildGenerateCode_C(glbBuild &context, const char* tag, std::string &codeOut)
1646 | {
1647 | if (tag == NULL) {
1648 | return GLB_INVALID_ARGS;
1649 | }
1650 |
1651 | glbResult result = GLB_INVALID_ARGS;
1652 | if (strcmp(tag, "/*<>*/") == 0) {
1653 | result = glbBuildGenerateCode_C_Main(context, codeOut);
1654 | }
1655 | if (strcmp(tag, "/*<>*/") == 0) {
1656 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal(context, 0, codeOut);
1657 | }
1658 | if (strcmp(tag, "/*<>*/") == 0) {
1659 | result = glbBuildGenerateCode_C_FuncPointersDeclGlobal(context, 4, codeOut);
1660 | }
1661 | if (strcmp(tag, "/*<>*/") == 0) {
1662 | result = glbBuildGenerateCode_C_InitCurrentContextAPI(context, codeOut);
1663 | }
1664 | if (strcmp(tag, "/*<>*/") == 0) {
1665 | result = glbBuildGenerateCode_C_SetGlobalAPIFromStruct(context, codeOut);
1666 | }
1667 | if (strcmp(tag, "<>") == 0) {
1668 | result = vkbBuildGenerateCode_C_OpenGLVersion(context, codeOut);
1669 | }
1670 | if (strcmp(tag, "<>") == 0) {
1671 | result = glbBuildGenerateCode_C_Revision(context, codeOut);
1672 | }
1673 | if (strcmp(tag, "<>") == 0) {
1674 | result = glbBuildGenerateCode_C_Date(context, codeOut);
1675 | }
1676 |
1677 | return result;
1678 | }
1679 |
1680 | glbResult glbBuildGenerateOutputFile(glbBuild &context, const char* outputFilePath)
1681 | {
1682 | // Before doing anything we need to grab the template.
1683 | size_t templateFileSize;
1684 | char* pTemplateFileData;
1685 | glbResult result = glbOpenAndReadTextFile(GLB_BUILD_TEMPLATE_PATH, &templateFileSize, &pTemplateFileData);
1686 | if (result != GLB_SUCCESS) {
1687 | return result;
1688 | }
1689 |
1690 | std::string outputStr = pTemplateFileData;
1691 | free(pTemplateFileData);
1692 |
1693 | // There will be a series of tags that we need to replace with generated code.
1694 | const char* tags[] = {
1695 | "/*<>*/",
1696 | "/*<>*/",
1697 | "/*<>*/",
1698 | "/*<>*/",
1699 | "/*<>*/",
1700 | "<>",
1701 | "<>",
1702 | "<>",
1703 | };
1704 |
1705 | for (size_t iTag = 0; iTag < sizeof(tags)/sizeof(tags[0]); ++iTag) {
1706 | std::string generatedCode;
1707 | result = glbBuildGenerateCode_C(context, tags[iTag], generatedCode);
1708 | if (result != GLB_SUCCESS) {
1709 | return result;
1710 | }
1711 |
1712 | glbReplaceAllInline(outputStr, tags[iTag], generatedCode);
1713 | }
1714 |
1715 | /* Normalize all occurances of Display and then convert to our alternate name. */
1716 | glbReplaceAllInline(outputStr, "glbind_Display*", "Display*");
1717 | glbReplaceAllInline(outputStr, "Display *", "Display*");
1718 | glbReplaceAllInline(outputStr, "Display*", "glbind_Display*");
1719 |
1720 | glbReplaceAllInline(outputStr, "glbind_XVisualInfo*", "XVisualInfo*");
1721 | glbReplaceAllInline(outputStr, "XVisualInfo *", "XVisualInfo*");
1722 | glbReplaceAllInline(outputStr, "XVisualInfo*", "glbind_XVisualInfo*");
1723 |
1724 | glbReplaceAllInline(outputStr, "glbind_Visual*", "Visual*");
1725 | glbReplaceAllInline(outputStr, "Visual *", "Visual*");
1726 | glbReplaceAllInline(outputStr, "Visual*", "glbind_Visual*");
1727 |
1728 | glbReplaceAllInline(outputStr, "glbind_XSetWindowAttributes*", "XSetWindowAttributes*");
1729 | glbReplaceAllInline(outputStr, "XSetWindowAttributes *", "XSetWindowAttributes*");
1730 | glbReplaceAllInline(outputStr, "XSetWindowAttributes*", "glbind_XSetWindowAttributes*");
1731 |
1732 | glbReplaceAllInline(outputStr, "glbind_XID", "XID");
1733 | glbReplaceAllInline(outputStr, "XID ", "glbind_XID ");
1734 | glbReplaceAllInline(outputStr, " XID;", " glbind_XID;");
1735 | glbReplaceAllInline(outputStr, "[XID]", "[glbind_XID]");
1736 | glbReplaceAllInline(outputStr, "[glbind_XID]", "XID");
1737 |
1738 | glbReplaceAllInline(outputStr, "glbind_Window", "Window");
1739 | glbReplaceAllInline(outputStr, "Window ", "glbind_Window ");
1740 | glbReplaceAllInline(outputStr, " Window;", " glbind_Window;");
1741 | glbReplaceAllInline(outputStr, "typedef glbind_Window", "typedef Window");
1742 | glbReplaceAllInline(outputStr, "GLXglbind_Window", "GLXWindow");
1743 | glbReplaceAllInline(outputStr, "glbind_Dummyglbind_Window", "glbind_DummyWindow");
1744 | glbReplaceAllInline(outputStr, "typedef Window (", "typedef glbind_Window (");
1745 | glbReplaceAllInline(outputStr, "glbind_XCreateglbind_Window", "glbind_XCreateWindow");
1746 | glbReplaceAllInline(outputStr, "glbind_XDestroyglbind_Window", "glbind_XDestroyWindow");
1747 | glbReplaceAllInline(outputStr, "glbind_XRootglbind_Window", "glbind_XRootWindow");
1748 | glbReplaceAllInline(outputStr, "glXCreateglbind_Window", "glXCreateWindow");
1749 | glbReplaceAllInline(outputStr, "glXDestroyglbind_Window", "glXDestroyWindow");
1750 |
1751 | glbReplaceAllInline(outputStr, "glbind_Colormap", "Colormap");
1752 | glbReplaceAllInline(outputStr, "Colormap ", "glbind_Colormap ");
1753 | glbReplaceAllInline(outputStr, " Colormap;", " glbind_Colormap;");
1754 | glbReplaceAllInline(outputStr, "typedef glbind_Colormap", "typedef Colormap");
1755 | glbReplaceAllInline(outputStr, "typedef Colormap (", "typedef glbind_Colormap (");
1756 | glbReplaceAllInline(outputStr, "glbind_XCreateglbind_Colormap", "glbind_XCreateColormap");
1757 | glbReplaceAllInline(outputStr, "glbind_XFreeglbind_Colormap", "glbind_XFreeColormap");
1758 | glbReplaceAllInline(outputStr, "glbind_Dummyglbind_Colormap", "glbind_DummyColormap");
1759 | glbReplaceAllInline(outputStr, "glbind_CWglbind_Colormap", "glbind_CWColormap");
1760 |
1761 | glbReplaceAllInline(outputStr, "glbind_Pixmap", "Pixmap");
1762 | glbReplaceAllInline(outputStr, "Pixmap ", "glbind_Pixmap ");
1763 | glbReplaceAllInline(outputStr, " Pixmap;", " glbind_Pixmap;");
1764 | glbReplaceAllInline(outputStr, "typedef glbind_Pixmap", "typedef Pixmap");
1765 | glbReplaceAllInline(outputStr, "GLXglbind_Pixmap", "GLXPixmap");
1766 | glbReplaceAllInline(outputStr, "glXCreateglbind_Pixmap", "glXCreatePixmap");
1767 | glbReplaceAllInline(outputStr, "glXDestroyglbind_Pixmap", "glXDestroyPixmap");
1768 |
1769 | glbReplaceAllInline(outputStr, "glbind_Font", "Font");
1770 | glbReplaceAllInline(outputStr, "Font ", "glbind_Font ");
1771 | glbReplaceAllInline(outputStr, " Font;", " glbind_Font;");
1772 | glbReplaceAllInline(outputStr, "typedef glbind_Font", "typedef Font");
1773 | glbReplaceAllInline(outputStr, "glXUseXglbind_Font", "glXUseXFont");
1774 |
1775 | glbReplaceAllInline(outputStr, "glbind_Atom", "Atom");
1776 | glbReplaceAllInline(outputStr, "Atom ", "glbind_Atom ");
1777 | glbReplaceAllInline(outputStr, " Atom;", " glbind_Atom;");
1778 | glbReplaceAllInline(outputStr, "typedef glbind_Atom", "typedef Atom");
1779 |
1780 | glbReplaceAllInline(outputStr, "glbind_Cursor", "Cursor");
1781 | glbReplaceAllInline(outputStr, "Cursor ", "glbind_Cursor ");
1782 | glbReplaceAllInline(outputStr, " Cursor;", " glbind_Cursor;");
1783 | glbReplaceAllInline(outputStr, "typedef glbind_Cursor", "typedef Cursor");
1784 |
1785 | glbReplaceAllInline(outputStr, "glbind_Bool", "Bool");
1786 | glbReplaceAllInline(outputStr, "Bool ", "glbind_Bool ");
1787 | glbReplaceAllInline(outputStr, " Bool;", " glbind_Bool;");
1788 | glbReplaceAllInline(outputStr, "typedef glbind_Bool", "typedef Bool");
1789 | glbReplaceAllInline(outputStr, "typedef Bool (", "typedef glbind_Bool (");
1790 |
1791 | glbReplaceAllInline(outputStr, "glbind_Status", "Status");
1792 | //glbReplaceAllInline(outputStr, "Status ", "glbind_Status ");
1793 | glbReplaceAllInline(outputStr, " Status;", " glbind_Status;");
1794 | glbReplaceAllInline(outputStr, "typedef glbind_Status", "typedef Status");
1795 | glbReplaceAllInline(outputStr, "typedef Status (", "typedef glbind_Status (");
1796 |
1797 | glbOpenAndWriteTextFile(outputFilePath, outputStr.c_str());
1798 | return GLB_SUCCESS;
1799 | }
1800 |
1801 |
1802 | int main(int argc, char** argv)
1803 | {
1804 | glbBuild context;
1805 | glbResult result;
1806 |
1807 | // GL
1808 | result = glbBuildLoadXMLFile(context, GLB_BUILD_XML_PATH_GL);
1809 | if (result != GLB_SUCCESS) {
1810 | return result;
1811 | }
1812 |
1813 | // WGL
1814 | result = glbBuildLoadXMLFile(context, GLB_BUILD_XML_PATH_WGL);
1815 | if (result != GLB_SUCCESS) {
1816 | return result;
1817 | }
1818 |
1819 | // GLX
1820 | result = glbBuildLoadXMLFile(context, GLB_BUILD_XML_PATH_GLX);
1821 | if (result != GLB_SUCCESS) {
1822 | return result;
1823 | }
1824 |
1825 |
1826 | // Debugging
1827 | #if 0
1828 | for (size_t i = 0; i < context.types.size(); ++i) {
1829 | printf(": name=%s, valueC=%s, requires=%s\n", context.types[i].name.c_str(), context.types[i].valueC.c_str(), context.types[i].requires.c_str());
1830 | }
1831 |
1832 | for (size_t i = 0; i < context.enums.size(); ++i) {
1833 | printf("\n");
1834 | for (size_t j = 0; j < context.enums[i].enums.size(); ++j) {
1835 | printf(" \n", context.enums[i].enums[j].name.c_str(), context.enums[i].enums[j].value.c_str());
1836 | }
1837 | printf("\n");
1838 | }
1839 |
1840 | for (size_t i = 0; i < context.groups.size(); ++i) {
1841 | printf("\n", context.groups[i].name.c_str());
1842 | for (size_t j = 0; j < context.groups[i].enums.size(); ++j) {
1843 | printf(" \n", context.groups[i].enums[j].name.c_str(), context.groups[i].enums[j].value.c_str());
1844 | }
1845 | printf("\n");
1846 | }
1847 |
1848 | for (size_t i = 0; i < context.commands.size(); ++i) {
1849 | printf("\n", context.commands[i].namespaceAttrib.c_str());
1850 | for (size_t j = 0; j < context.commands[i].commands.size(); ++j) {
1851 | printf(" %s %s()\n", context.commands[i].commands[j].returnTypeC.c_str(), context.commands[i].commands[j].name.c_str());
1852 | }
1853 | printf("\n");
1854 | }
1855 | #endif
1856 |
1857 |
1858 | // Output file.
1859 | result = glbBuildGenerateOutputFile(context, "glbind.h");
1860 | if (result != GLB_SUCCESS) {
1861 | printf("Failed to generate output file.\n");
1862 | return (int)result;
1863 | }
1864 |
1865 | // Getting here means we're done.
1866 | (void)argc;
1867 | (void)argv;
1868 | return 0;
1869 | }
--------------------------------------------------------------------------------
/source/glbind_template.h:
--------------------------------------------------------------------------------
1 | /*
2 | OpenGL API loader. Choice of public domain or MIT-0. See license statements at the end of this file.
3 | glbind - v<>.<> - <>
4 |
5 | David Reid - davidreidsoftware@gmail.com
6 | */
7 |
8 | #ifndef GLBIND_H
9 | #define GLBIND_H
10 |
11 | #ifdef __cplusplus
12 | extern "C" {
13 | #endif
14 |
15 | /* For platform detection, I'm just assuming GLX if it's not Win32. Happy to look at making this more flexible, especially when it comes to GLES. */
16 | #if defined(_WIN32)
17 | #define GLBIND_WGL
18 | #else
19 | #define GLBIND_GLX
20 | #endif
21 |
22 | /*
23 | The official OpenGL headers have a dependency on a header called khrplatform.h. From what I can see it's mainly just for sized types. Since glbind is a
24 | single header, and that we can't just copy-and-paste the contents of khrplatform.h due to licensing, we need to do our own sized type declarations.
25 | */
26 | #ifndef __khrplatform_h_
27 | #include /* For size_t. */
28 | #ifdef _MSC_VER
29 | #if defined(__clang__)
30 | #pragma GCC diagnostic push
31 | #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
32 | #pragma GCC diagnostic ignored "-Wc++11-long-long"
33 | #endif
34 | typedef signed __int8 khronos_int8_t;
35 | typedef unsigned __int8 khronos_uint8_t;
36 | typedef signed __int16 khronos_int16_t;
37 | typedef unsigned __int16 khronos_uint16_t;
38 | typedef signed __int32 khronos_int32_t;
39 | typedef unsigned __int32 khronos_uint32_t;
40 | typedef signed __int64 khronos_int64_t;
41 | typedef unsigned __int64 khronos_uint64_t;
42 | #if defined(__clang__)
43 | #pragma GCC diagnostic pop
44 | #endif
45 | #else
46 | #define MA_HAS_STDINT
47 | #include
48 | typedef int8_t khronos_int8_t;
49 | typedef uint8_t khronos_uint8_t;
50 | typedef int16_t khronos_int16_t;
51 | typedef uint16_t khronos_uint16_t;
52 | typedef int32_t khronos_int32_t;
53 | typedef uint32_t khronos_uint32_t;
54 | typedef int64_t khronos_int64_t;
55 | typedef uint64_t khronos_uint64_t;
56 | #endif
57 |
58 | #ifdef MA_HAS_STDINT
59 | typedef uintptr_t khronos_uintptr_t;
60 | typedef intptr_t khronos_intptr_t;
61 | typedef uintptr_t khronos_usize_t;
62 | typedef intptr_t khronos_ssize_t;
63 | #else
64 | #if defined(_WIN32)
65 | #if defined(_WIN64)
66 | typedef khronos_uint64_t khronos_uintptr_t;
67 | typedef khronos_int64_t khronos_intptr_t;
68 | typedef khronos_uint64_t khronos_usize_t;
69 | typedef khronos_int64_t khronos_ssize_t;
70 | #else
71 | typedef khronos_uint32_t khronos_uintptr_t;
72 | typedef khronos_int32_t khronos_intptr_t;
73 | typedef khronos_uint32_t khronos_usize_t;
74 | typedef khronos_int32_t khronos_ssize_t;
75 | #endif
76 | #elif defined(__GNUC__)
77 | #if defined(__LP64__)
78 | typedef khronos_uint64_t khronos_uintptr_t;
79 | typedef khronos_int64_t khronos_intptr_t;
80 | typedef khronos_uint64_t khronos_usize_t;
81 | typedef khronos_int64_t khronos_ssize_t;
82 | #else
83 | typedef khronos_uint32_t khronos_uintptr_t;
84 | typedef khronos_int32_t khronos_intptr_t;
85 | typedef khronos_uint32_t khronos_usize_t;
86 | typedef khronos_int32_t khronos_ssize_t;
87 | #endif
88 | #else
89 | typedef khronos_uint64_t khronos_uintptr_t;
90 | typedef khronos_int64_t khronos_intptr_t;
91 | typedef khronos_uint64_t khronos_usize_t; /* Fallback. */
92 | typedef khronos_int64_t khronos_ssize_t;
93 | #endif
94 | #endif
95 | typedef float khronos_float_t;
96 | #endif /* __khrplatform_h_ */
97 |
98 | /* Platform headers. */
99 | #if defined(GLBIND_WGL)
100 | #include /* Can we remove this dependency? */
101 | #endif
102 | #if defined(GLBIND_GLX)
103 | #if !defined(GLBIND_NO_XLIB_HEADERS)
104 | #include
105 | #include
106 |
107 | typedef Display glbind_Display;
108 | typedef Visual glbind_Visual;
109 | typedef VisualID glbind_VisualID;
110 | typedef XVisualInfo glbind_XVisualInfo;
111 | typedef XSetWindowAttributes glbind_XSetWindowAttributes;
112 | typedef [XID] glbind_XID;
113 | typedef Window glbind_Window;
114 | typedef Colormap glbind_Colormap;
115 | typedef Pixmap glbind_Pixmap;
116 | typedef Font glbind_Font;
117 | typedef Atom glbind_Atom;
118 | typedef Cursor glbind_Cursor;
119 | typedef Bool glbind_Bool;
120 | typedef Status glbind_Status;
121 |
122 | #define glbind_None None
123 | #define glbind_AllocNone AllocNone
124 |
125 | #define glbind_CWBorderPixel CWBorderPixel
126 | #define glbind_CWColormap CWColormap
127 |
128 | #define glbind_InputOutput InputOutput
129 | #else
130 | typedef void* glbind_Display;
131 | typedef void* glbind_Visual;
132 | typedef unsigned long glbind_VisualID;
133 | typedef unsigned long glbind_XID;
134 | typedef glbind_XID glbind_Window;
135 | typedef glbind_XID glbind_Colormap;
136 | typedef glbind_XID glbind_Pixmap;
137 | typedef glbind_XID glbind_Font;
138 | typedef glbind_XID glbind_Atom;
139 | typedef glbind_XID glbind_Cursor;
140 | typedef int glbind_Bool;
141 | typedef int glbind_Status;
142 |
143 | #define glbind_None 0
144 | #define glbind_AllocNone 0
145 |
146 | #define glbind_CWBorderPixel (1 << 3)
147 | #define glbind_CWColormap (1 << 13)
148 |
149 | #define glbind_InputOutput 1
150 |
151 |
152 | /* We need to declare our own version of XVisualInfo */
153 | typedef struct
154 | {
155 | glbind_Visual* visual;
156 | glbind_VisualID visualid;
157 | int screen;
158 | int depth;
159 | int class;
160 | unsigned long red_mask;
161 | unsigned long green_mask;
162 | unsigned long blue_mask;
163 | int colormap_size;
164 | int bits_per_rgb;
165 | } glbind_XVisualInfo;
166 |
167 | /* We need to declare our own version of XSetWindowAttributes */
168 | typedef struct
169 | {
170 | glbind_Pixmap background_pixmap;
171 | unsigned long background_pixel;
172 | glbind_Pixmap border_pixmap;
173 | unsigned long border_pixel;
174 | int bit_gravity;
175 | int win_gravity;
176 | int backing_store;
177 | unsigned long backing_planes;
178 | unsigned long backing_pixel;
179 | int save_under;
180 | long event_mask;
181 | long do_not_propagate_mask;
182 | int override_redirect;
183 | glbind_Colormap colormap;
184 | glbind_Cursor cursor;
185 | } glbind_XSetWindowAttributes;
186 | #endif
187 | #endif
188 |
189 | /*
190 | The official OpenGL headers have traditionally defined their APIs with APIENTRY, APIENTRYP and GLAPI. I'm including these just in case
191 | some program wants to use them.
192 | */
193 | #ifndef APIENTRY
194 | #define APIENTRY
195 | #endif
196 | #ifndef APIENTRYP
197 | #define APIENTRYP APIENTRY *
198 | #endif
199 | #ifndef GLAPI
200 | #define GLAPI extern
201 | #endif
202 |
203 |
204 |
205 | /*<>*/
206 |
207 | /*<>*/
208 |
209 | typedef struct
210 | {
211 | /*<>*/
212 | } GLBapi;
213 |
214 | typedef struct
215 | {
216 | GLboolean singleBuffered;
217 | #if defined(GLBIND_WGL)
218 | HWND hWnd;
219 | #endif
220 | #if defined(GLBIND_GLX)
221 | glbind_Display* pDisplay;
222 | #endif
223 | } GLBconfig;
224 |
225 | /*
226 | Initializes a config object which can later be passed to glbInit() to configure the rendering context that's created by glbInit().
227 | */
228 | GLBconfig glbConfigInit(void);
229 |
230 | /*
231 | Initializes glbind and attempts to load APIs statically.
232 |
233 | pAPI is optional. On output it will contain pointers to all OpenGL APIs found by the loader.
234 |
235 | This will initialize a dummy rendering context and make it current. It will also bind API's to global scope. If you want to load
236 | APIs based on a specific rendering context, use glbInitContextAPI(). Then you can, optionally, call glbBindAPI() to bind those
237 | APIs to global scope.
238 |
239 | This is not thread-safe. You can call this multiple times, but each call must be matched with a call to glbUninit(). The first
240 | time this is called it will bind the APIs to global scope.
241 |
242 | The internal rendering context can be used like normal. It will be created in double-buffered mode. You can also create your own
243 | context, but you may want to consider calling glbInitContextAPI() or glbInitCurrentContextAPI() after the fact to ensure function
244 | pointers are valid for that context.
245 |
246 | You can configure the internal rendering context by specifying a GLBconfig object. This can NULL in which case it will use
247 | defaults. Initialize the config object with glbConfigInit(). The default config creates a context with 32-bit color, 24-bit depth,
248 | 8-bit stencil and double-buffered.
249 | */
250 | GLenum glbInit(GLBapi* pAPI, GLBconfig* pConfig);
251 |
252 | /*
253 | Loads context-specific APIs into the specified API object.
254 |
255 | This does not bind these APIs to global scope. Use glbBindAPI() for this.
256 | */
257 | #if defined(GLBIND_WGL)
258 | GLenum glbInitContextAPI(HDC dc, HGLRC rc, GLBapi* pAPI);
259 | #endif
260 | #if defined(GLBIND_GLX)
261 | GLenum glbInitContextAPI(glbind_Display* dpy, GLXDrawable drawable, GLXContext rc, GLBapi* pAPI);
262 | #endif
263 |
264 | /*
265 | Loads context-specific APIs from the current context into the specified API object.
266 |
267 | This does not bind these APIs to global scope. Use glbBindAPI() for this.
268 | */
269 | GLenum glbInitCurrentContextAPI(GLBapi* pAPI);
270 |
271 | /*
272 | Uninitializes glbind.
273 |
274 | Each call to glbInit() must be matched up with a call to glbUninit().
275 | */
276 | void glbUninit(void);
277 |
278 | /*
279 | Binds the function pointers in pAPI to global scope.
280 | */
281 | GLenum glbBindAPI(const GLBapi* pAPI);
282 |
283 | /* Platform-specific APIs. */
284 | #if defined(GLBIND_WGL)
285 | /*
286 | Retrieves the rendering context that was created on the first call to glbInit().
287 | */
288 | HGLRC glbGetRC(void);
289 |
290 | /*
291 | Retrieves the device context of the dummy window that was created with the first call to glbInit().
292 |
293 | You can use this function for creating another rendering context without having to create your own dummy window.
294 | */
295 | HDC glbGetDC(void);
296 |
297 | /*
298 | Retrieves the pixel format that's being used by the rendering context that was created on the first call to glbInit().
299 | */
300 | int glbGetPixelFormat(void);
301 |
302 | /*
303 | Retrieves the pixel format descriptor being used by the rendering context that was created on the first call to glbInit().
304 | */
305 | PIXELFORMATDESCRIPTOR* glbGetPFD(void);
306 | #endif
307 |
308 | #if defined(GLBIND_GLX)
309 | /*
310 | Retrieves a reference to the global Display that was created with the first call to glbInit(). If the display was set
311 | in the config object, that Display will be returned.
312 | */
313 | glbind_Display* glbGetDisplay(void);
314 |
315 | /*
316 | Retrieves the rendering context that was created on the first call to glbInit().
317 | */
318 | GLXContext glbGetRC(void);
319 |
320 | /*
321 | Retrieves the color map that was created on the first call to glbInit().
322 | */
323 | Colormap glbGetColormap(void);
324 |
325 | /*
326 | Retrieves the framebuffer visual info that was created on the first call to glbInit().
327 | */
328 | XVisualInfo* glbGetFBVisualInfo(void);
329 | #endif
330 |
331 | #ifdef __cplusplus
332 | }
333 | #endif
334 |
335 | /*
336 | Helper API for checking if an extension is supported based on the current rendering context.
337 |
338 | This checks cross-platform extensions, WGL extensions and GLX extensions (in that order).
339 |
340 | pAPI is optional. If non-null, this relevant APIs from this object will be used. Otherwise, whatever is bound to global
341 | scope will be used.
342 | */
343 | GLboolean glbIsExtensionSupported(GLBapi* pAPI, const char* extensionName);
344 |
345 | #endif /* GLBIND_H */
346 |
347 |
348 | /******************************************************************************
349 | ******************************************************************************
350 |
351 | IMPLEMENTATION
352 |
353 | ******************************************************************************
354 | ******************************************************************************/
355 | #ifdef GLBIND_IMPLEMENTATION
356 | #if defined(GLBIND_WGL)
357 | #endif
358 | #if defined(GLBIND_GLX)
359 | #include
360 | #include
361 | #endif
362 |
363 | typedef void* GLBhandle;
364 | typedef void (* GLBproc)(void);
365 |
366 | void glbZeroMemory(void* p, size_t sz)
367 | {
368 | size_t i;
369 | for (i = 0; i < sz; ++i) {
370 | ((GLbyte*)p)[i] = 0;
371 | }
372 | }
373 |
374 | #define glbZeroObject(p) glbZeroMemory((p), sizeof(*(p)));
375 |
376 | GLBhandle glb_dlopen(const char* filename)
377 | {
378 | #ifdef _WIN32
379 | return (GLBhandle)LoadLibraryA(filename);
380 | #else
381 | return (GLBhandle)dlopen(filename, RTLD_NOW);
382 | #endif
383 | }
384 |
385 | void glb_dlclose(GLBhandle handle)
386 | {
387 | #ifdef _WIN32
388 | FreeLibrary((HMODULE)handle);
389 | #else
390 | dlclose((void*)handle);
391 | #endif
392 | }
393 |
394 | GLBproc glb_dlsym(GLBhandle handle, const char* symbol)
395 | {
396 | #ifdef _WIN32
397 | return (GLBproc)GetProcAddress((HMODULE)handle, symbol);
398 | #else
399 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
400 | #pragma GCC diagnostic push
401 | #pragma GCC diagnostic ignored "-Wpedantic"
402 | #endif
403 | return (GLBproc)dlsym((void*)handle, symbol);
404 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
405 | #pragma GCC diagnostic pop
406 | #endif
407 | #endif
408 | }
409 |
410 |
411 | static unsigned int g_glbInitCount = 0;
412 | static GLBhandle g_glbOpenGLSO = NULL;
413 |
414 | #if defined(GLBIND_WGL)
415 | HWND glbind_DummyHWND = 0;
416 | HDC glbind_DC = 0;
417 | HGLRC glbind_RC = 0;
418 | PIXELFORMATDESCRIPTOR glbind_PFD;
419 | int glbind_PixelFormat;
420 |
421 | static LRESULT GLBIND_DummyWindowProcWin32(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
422 | {
423 | return DefWindowProc(hWnd, msg, wParam, lParam);
424 | }
425 | #endif
426 | #if defined(GLBIND_GLX)
427 | glbind_Display* glbind_pDisplay = 0;
428 | glbind_Window glbind_DummyWindow = 0;
429 | GLXContext glbind_RC = 0;
430 | glbind_Colormap glbind_DummyColormap = 0;
431 | glbind_XVisualInfo* glbind_pFBVisualInfo = 0;
432 | GLboolean glbind_OwnsDisplay = GL_FALSE;
433 | #endif
434 |
435 | #if defined(GLBIND_WGL)
436 | PFNWGLCREATECONTEXTPROC glbind_wglCreateContext;
437 | PFNWGLDELETECONTEXTPROC glbind_wglDeleteContext;
438 | PFNWGLGETCURRENTCONTEXTPROC glbind_wglGetCurrentContext;
439 | PFNWGLGETCURRENTDCPROC glbind_wglGetCurrentDC;
440 | PFNWGLGETPROCADDRESSPROC glbind_wglGetProcAddress;
441 | PFNWGLMAKECURRENTPROC glbind_wglMakeCurrent;
442 |
443 | static GLBhandle g_glbGdi32DLL = NULL;
444 | PFNCHOOSEPIXELFORMATPROC glbind_ChoosePixelFormat;
445 | PFNSETPIXELFORMATPROC glbind_SetPixelFormat;
446 | PFNSWAPBUFFERSPROC glbind_SwapBuffers;
447 | #endif
448 | #if defined(GLBIND_GLX)
449 | /* We need to define our own function types for the glX*() functions so they use our glbind_Display, etc. types instead of the normal types. */
450 | typedef glbind_XVisualInfo* (* GLB_PFNGLXCHOOSEVISUALPROC) (glbind_Display* pDisplay, int screen, int* pAttribList);
451 | typedef GLXContext (* GLB_PFNGLXCREATECONTEXTPROC) (glbind_Display* pDisplay, glbind_XVisualInfo* pVisual, GLXContext shareList, GLboolean direct);
452 | typedef void (* GLB_PFNGLXDESTROYCONTEXTPROC) (glbind_Display* pDisplay, GLXContext context);
453 | typedef GLboolean (* GLB_PFNGLXMAKECURRENTPROC) (glbind_Display* pDisplay, GLXDrawable drawable, GLXContext context);
454 | typedef void (* GLB_PFNGLXSWAPBUFFERSPROC) (glbind_Display* pDisplay, GLXDrawable drawable);
455 | typedef GLXContext (* GLB_PFNGLXGETCURRENTCONTEXTPROC) (void);
456 | typedef const char* (* GLB_PFNGLXQUERYEXTENSIONSSTRINGPROC)(glbind_Display* pDisplay, int screen);
457 | typedef glbind_Display* (* GLB_PFNGLXGETCURRENTDISPLAYPROC) (void);
458 | typedef GLXDrawable (* GLB_PFNGLXGETCURRENTDRAWABLEPROC) (void);
459 | typedef glbind_XVisualInfo* (* GLB_PFNGLXGETVISUALFROMFBCONFIGPROC)(glbind_Display* pDisplay, GLXFBConfig config);
460 | typedef GLXFBConfig* (* GLB_PFNGLXCHOOSEFBCONFIGPROC) (glbind_Display* pDisplay, int screen, const int* pAttribList, int* pCount);
461 | typedef GLBproc (* GLB_PFNGLXGETPROCADDRESSPROC) (const GLubyte* pName);
462 |
463 | /* Declare our global functions using the types above. */
464 | GLB_PFNGLXCHOOSEVISUALPROC glbind_glXChooseVisual;
465 | GLB_PFNGLXCREATECONTEXTPROC glbind_glXCreateContext;
466 | GLB_PFNGLXDESTROYCONTEXTPROC glbind_glXDestroyContext;
467 | GLB_PFNGLXMAKECURRENTPROC glbind_glXMakeCurrent;
468 | GLB_PFNGLXSWAPBUFFERSPROC glbind_glXSwapBuffers;
469 | GLB_PFNGLXGETCURRENTCONTEXTPROC glbind_glXGetCurrentContext;
470 | GLB_PFNGLXQUERYEXTENSIONSSTRINGPROC glbind_glXQueryExtensionsString;
471 | GLB_PFNGLXGETCURRENTDISPLAYPROC glbind_glXGetCurrentDisplay;
472 | GLB_PFNGLXGETCURRENTDRAWABLEPROC glbind_glXGetCurrentDrawable;
473 | GLB_PFNGLXGETVISUALFROMFBCONFIGPROC glbind_glXGetVisualFromFBConfig;
474 | GLB_PFNGLXCHOOSEFBCONFIGPROC glbind_glXChooseFBConfig;
475 | GLB_PFNGLXGETPROCADDRESSPROC glbind_glXGetProcAddress;
476 |
477 |
478 | static GLBhandle g_glbX11SO = NULL;
479 | typedef glbind_Display* (* GLB_PFNXOPENDISPLAYPROC) (const char* pDisplayName);
480 | typedef int (* GLB_PFNXCLOSEDISPLAYPROC) (glbind_Display* pDisplay);
481 | typedef glbind_Window (* GLB_PFNXCREATEWINDOWPROC) (glbind_Display* pDisplay, glbind_Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int borderWidth, int depth, unsigned int windowClass, glbind_Visual* pVisual, unsigned long valueMask, XSetWindowAttributes* pAttributes);
482 | typedef int (* GLB_PFNXDESTROYWINDOWPROC) (glbind_Display* pDisplay, glbind_Window window);
483 | typedef glbind_Colormap (* GLB_PFNXCREATECOLORMAPPROC)(glbind_Display* pDisplay, glbind_Window window, glbind_Visual* pVisual, int alloc);
484 | typedef int (* GLB_PFNXFREECOLORMAPPROC) (glbind_Display* pDisplay, glbind_Colormap colormap);
485 | typedef int (* GLB_PFNXDEFAULTSCREENPROC) (glbind_Display* pDisplay);
486 | typedef glbind_Window (* GLB_PFNXROOTWINDOWPROC) (glbind_Display* pDisplay, int screenNumber);
487 |
488 | GLB_PFNXOPENDISPLAYPROC glbind_XOpenDisplay;
489 | GLB_PFNXCLOSEDISPLAYPROC glbind_XCloseDisplay;
490 | GLB_PFNXCREATEWINDOWPROC glbind_XCreateWindow;
491 | GLB_PFNXDESTROYWINDOWPROC glbind_XDestroyWindow;
492 | GLB_PFNXCREATECOLORMAPPROC glbind_XCreateColormap;
493 | GLB_PFNXFREECOLORMAPPROC glbind_XFreeColormap;
494 | GLB_PFNXDEFAULTSCREENPROC glbind_XDefaultScreen;
495 | GLB_PFNXROOTWINDOWPROC glbind_XRootWindow;
496 | #endif
497 |
498 | GLBproc glbGetProcAddress(const char* name)
499 | {
500 | GLBproc func = NULL;
501 | #if defined(GLBIND_WGL)
502 | if (glbind_wglGetProcAddress) {
503 | func = (GLBproc)glbind_wglGetProcAddress(name);
504 | }
505 | #endif
506 | #if defined(GLBIND_GLX)
507 | if (glbind_glXGetProcAddress) {
508 | func = (GLBproc)glbind_glXGetProcAddress((const GLubyte*)name);
509 | }
510 | #endif
511 |
512 | if (func == NULL) {
513 | func = glb_dlsym(g_glbOpenGLSO, name);
514 | }
515 |
516 | return func;
517 | }
518 |
519 | GLenum glbLoadOpenGLSO(void)
520 | {
521 | GLenum result;
522 | size_t i;
523 |
524 | const char* openGLSONames[] = {
525 | #if defined(_WIN32)
526 | "OpenGL32.dll"
527 | #elif defined(__APPLE__)
528 | #else
529 | "libGL.so.1",
530 | "libGL.so"
531 | #endif
532 | };
533 |
534 | result = GL_INVALID_OPERATION;
535 | for (i = 0; i < sizeof(openGLSONames)/sizeof(openGLSONames[0]); ++i) {
536 | GLBhandle handle = glb_dlopen(openGLSONames[i]);
537 | if (handle != NULL) {
538 | g_glbOpenGLSO = handle;
539 | result = GL_NO_ERROR;
540 | break;
541 | }
542 | }
543 |
544 | if (result != GL_NO_ERROR) {
545 | return result;
546 | }
547 |
548 | /* Runtime linking for platform-specific libraries. */
549 | {
550 | #if defined(_WIN32)
551 | /* Win32 */
552 | g_glbGdi32DLL = glb_dlopen("gdi32.dll");
553 | if (g_glbGdi32DLL == NULL) {
554 | glb_dlclose(g_glbOpenGLSO);
555 | g_glbOpenGLSO = NULL;
556 | return GL_INVALID_OPERATION;
557 | }
558 | #elif defined(__APPLE_)
559 | /* Apple */
560 | #else
561 | /* X11 */
562 | const char* x11SONames[] = {
563 | "libX11.so",
564 | "libX11.so.6"
565 | };
566 |
567 | result = GL_INVALID_OPERATION;
568 | for (i = 0; i < sizeof(openGLSONames)/sizeof(openGLSONames[0]); ++i) {
569 | GLBhandle handle = glb_dlopen(x11SONames[i]);
570 | if (handle != NULL) {
571 | g_glbX11SO = handle;
572 | result = GL_NO_ERROR;
573 | break;
574 | }
575 | }
576 | #endif
577 | }
578 |
579 | if (result != GL_NO_ERROR) {
580 | glb_dlclose(g_glbOpenGLSO);
581 | g_glbOpenGLSO = NULL;
582 | }
583 |
584 | return result;
585 | }
586 |
587 | void glbUnloadOpenGLSO(void)
588 | {
589 | if (g_glbOpenGLSO == NULL) {
590 | return;
591 | }
592 |
593 | /* Unload platform-specific libraries. */
594 | {
595 | #if defined(_WIN32)
596 | /* Win32 */
597 | glb_dlclose(g_glbGdi32DLL);
598 | g_glbGdi32DLL = NULL;
599 | #elif defined(__APPLE_)
600 | /* Apple */
601 | #else
602 | /* X11 */
603 | glb_dlclose(g_glbX11SO);
604 | g_glbX11SO = NULL;
605 | #endif
606 | }
607 |
608 | glb_dlclose(g_glbOpenGLSO);
609 | g_glbOpenGLSO = NULL;
610 | }
611 |
612 | GLBconfig glbConfigInit(void)
613 | {
614 | GLBconfig config;
615 | glbZeroObject(&config);
616 |
617 | return config;
618 | }
619 |
620 | GLenum glbInit(GLBapi* pAPI, GLBconfig* pConfig)
621 | {
622 | GLenum result;
623 |
624 | if (g_glbInitCount == 0) {
625 | result = glbLoadOpenGLSO();
626 | if (result != GL_NO_ERROR) {
627 | return result;
628 | }
629 |
630 | /* Here is where we need to initialize some core APIs. We need these to initialize dummy objects and whatnot. */
631 | #if defined(GLBIND_WGL)
632 | glbind_wglCreateContext = (PFNWGLCREATECONTEXTPROC )glb_dlsym(g_glbOpenGLSO, "wglCreateContext");
633 | glbind_wglDeleteContext = (PFNWGLDELETECONTEXTPROC )glb_dlsym(g_glbOpenGLSO, "wglDeleteContext");
634 | glbind_wglGetCurrentContext = (PFNWGLGETCURRENTCONTEXTPROC)glb_dlsym(g_glbOpenGLSO, "wglGetCurrentContext");
635 | glbind_wglGetCurrentDC = (PFNWGLGETCURRENTDCPROC )glb_dlsym(g_glbOpenGLSO, "wglGetCurrentDC");
636 | glbind_wglGetProcAddress = (PFNWGLGETPROCADDRESSPROC )glb_dlsym(g_glbOpenGLSO, "wglGetProcAddress");
637 | glbind_wglMakeCurrent = (PFNWGLMAKECURRENTPROC )glb_dlsym(g_glbOpenGLSO, "wglMakeCurrent");
638 |
639 | if (glbind_wglCreateContext == NULL ||
640 | glbind_wglDeleteContext == NULL ||
641 | glbind_wglGetCurrentContext == NULL ||
642 | glbind_wglGetCurrentDC == NULL ||
643 | glbind_wglGetProcAddress == NULL ||
644 | glbind_wglMakeCurrent == NULL) {
645 | glbUnloadOpenGLSO();
646 | return GL_INVALID_OPERATION;
647 | }
648 |
649 | glbind_ChoosePixelFormat = (PFNCHOOSEPIXELFORMATPROC)glb_dlsym(g_glbGdi32DLL, "ChoosePixelFormat");
650 | glbind_SetPixelFormat = (PFNSETPIXELFORMATPROC )glb_dlsym(g_glbGdi32DLL, "SetPixelFormat");
651 | glbind_SwapBuffers = (PFNSWAPBUFFERSPROC )glb_dlsym(g_glbGdi32DLL, "SwapBuffers");
652 |
653 | if (glbind_ChoosePixelFormat == NULL ||
654 | glbind_SetPixelFormat == NULL ||
655 | glbind_SwapBuffers == NULL) {
656 | glbUnloadOpenGLSO();
657 | return GL_INVALID_OPERATION;
658 | }
659 | #endif
660 | #if defined(GLBIND_GLX)
661 | glbind_glXChooseVisual = (GLB_PFNGLXCHOOSEVISUALPROC )glb_dlsym(g_glbOpenGLSO, "glXChooseVisual");
662 | glbind_glXCreateContext = (GLB_PFNGLXCREATECONTEXTPROC )glb_dlsym(g_glbOpenGLSO, "glXCreateContext");
663 | glbind_glXDestroyContext = (GLB_PFNGLXDESTROYCONTEXTPROC )glb_dlsym(g_glbOpenGLSO, "glXDestroyContext");
664 | glbind_glXMakeCurrent = (GLB_PFNGLXMAKECURRENTPROC )glb_dlsym(g_glbOpenGLSO, "glXMakeCurrent");
665 | glbind_glXSwapBuffers = (GLB_PFNGLXSWAPBUFFERSPROC )glb_dlsym(g_glbOpenGLSO, "glXSwapBuffers");
666 | glbind_glXGetCurrentContext = (GLB_PFNGLXGETCURRENTCONTEXTPROC )glb_dlsym(g_glbOpenGLSO, "glXGetCurrentContext");
667 | glbind_glXQueryExtensionsString = (GLB_PFNGLXQUERYEXTENSIONSSTRINGPROC)glb_dlsym(g_glbOpenGLSO, "glXQueryExtensionsString");
668 | glbind_glXGetCurrentDisplay = (GLB_PFNGLXGETCURRENTDISPLAYPROC )glb_dlsym(g_glbOpenGLSO, "glXGetCurrentDisplay");
669 | glbind_glXGetCurrentDrawable = (GLB_PFNGLXGETCURRENTDRAWABLEPROC )glb_dlsym(g_glbOpenGLSO, "glXGetCurrentDrawable");
670 | glbind_glXChooseFBConfig = (GLB_PFNGLXCHOOSEFBCONFIGPROC )glb_dlsym(g_glbOpenGLSO, "glXChooseFBConfig");
671 | glbind_glXGetVisualFromFBConfig = (GLB_PFNGLXGETVISUALFROMFBCONFIGPROC)glb_dlsym(g_glbOpenGLSO, "glXGetVisualFromFBConfig");
672 | glbind_glXGetProcAddress = (GLB_PFNGLXGETPROCADDRESSPROC )glb_dlsym(g_glbOpenGLSO, "glXGetProcAddress");
673 |
674 | if (glbind_glXChooseVisual == NULL ||
675 | glbind_glXCreateContext == NULL ||
676 | glbind_glXDestroyContext == NULL ||
677 | glbind_glXMakeCurrent == NULL ||
678 | glbind_glXSwapBuffers == NULL ||
679 | glbind_glXGetCurrentContext == NULL ||
680 | glbind_glXQueryExtensionsString == NULL ||
681 | glbind_glXGetCurrentDisplay == NULL ||
682 | glbind_glXGetCurrentDrawable == NULL ||
683 | glbind_glXChooseFBConfig == NULL ||
684 | glbind_glXGetVisualFromFBConfig == NULL ||
685 | glbind_glXGetProcAddress == NULL) {
686 | glbUnloadOpenGLSO();
687 | return GL_INVALID_OPERATION;
688 | }
689 |
690 | glbind_XOpenDisplay = (GLB_PFNXOPENDISPLAYPROC )glb_dlsym(g_glbX11SO, "XOpenDisplay");
691 | glbind_XCloseDisplay = (GLB_PFNXCLOSEDISPLAYPROC )glb_dlsym(g_glbX11SO, "XCloseDisplay");
692 | glbind_XCreateWindow = (GLB_PFNXCREATEWINDOWPROC )glb_dlsym(g_glbX11SO, "XCreateWindow");
693 | glbind_XDestroyWindow = (GLB_PFNXDESTROYWINDOWPROC )glb_dlsym(g_glbX11SO, "XDestroyWindow");
694 | glbind_XCreateColormap = (GLB_PFNXCREATECOLORMAPPROC)glb_dlsym(g_glbX11SO, "XCreateColormap");
695 | glbind_XFreeColormap = (GLB_PFNXFREECOLORMAPPROC )glb_dlsym(g_glbX11SO, "XFreeColormap");
696 | glbind_XDefaultScreen = (GLB_PFNXDEFAULTSCREENPROC )glb_dlsym(g_glbX11SO, "XDefaultScreen");
697 | glbind_XRootWindow = (GLB_PFNXROOTWINDOWPROC )glb_dlsym(g_glbX11SO, "XRootWindow");
698 |
699 | if (glbind_XOpenDisplay == NULL ||
700 | glbind_XCloseDisplay == NULL ||
701 | glbind_XCreateWindow == NULL ||
702 | glbind_XDestroyWindow == NULL ||
703 | glbind_XCreateColormap == NULL ||
704 | glbind_XFreeColormap == NULL ||
705 | glbind_XDefaultScreen == NULL ||
706 | glbind_XRootWindow == NULL) {
707 | glbUnloadOpenGLSO();
708 | return GL_INVALID_OPERATION;
709 | }
710 | #endif
711 |
712 | /* Here is where we need to initialize our dummy objects so we can get a context and retrieve some API pointers. */
713 | #if defined(GLBIND_WGL)
714 | {
715 | HWND hWnd = NULL;
716 |
717 | if (pConfig != NULL) {
718 | hWnd = pConfig->hWnd;
719 | }
720 |
721 | /* Create a dummy window if we haven't passed in an explicit window. */
722 | if (hWnd == NULL) {
723 | WNDCLASSEXW dummyWC;
724 | memset(&dummyWC, 0, sizeof(dummyWC));
725 | dummyWC.cbSize = sizeof(dummyWC);
726 | dummyWC.lpfnWndProc = (WNDPROC)GLBIND_DummyWindowProcWin32;
727 | dummyWC.lpszClassName = L"GLBIND_DummyHWND";
728 | dummyWC.style = CS_OWNDC;
729 | if (!RegisterClassExW(&dummyWC)) {
730 | glbUnloadOpenGLSO();
731 | return GL_INVALID_OPERATION;
732 | }
733 |
734 | hWnd = CreateWindowExW(0, L"GLBIND_DummyHWND", L"", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
735 | glbind_DummyHWND = hWnd;
736 | }
737 |
738 | glbind_DC = GetDC(hWnd);
739 |
740 | memset(&glbind_PFD, 0, sizeof(glbind_PFD));
741 | glbind_PFD.nSize = sizeof(glbind_PFD);
742 | glbind_PFD.nVersion = 1;
743 | glbind_PFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | ((pConfig == NULL || pConfig->singleBuffered == GL_FALSE) ? PFD_DOUBLEBUFFER : 0);
744 | glbind_PFD.iPixelType = PFD_TYPE_RGBA;
745 | glbind_PFD.cStencilBits = 8;
746 | glbind_PFD.cDepthBits = 24;
747 | glbind_PFD.cColorBits = 32;
748 | glbind_PixelFormat = glbind_ChoosePixelFormat(glbind_DC, &glbind_PFD);
749 | if (glbind_PixelFormat == 0) {
750 | DestroyWindow(hWnd);
751 | glbUnloadOpenGLSO();
752 | return GL_INVALID_OPERATION;
753 | }
754 |
755 | if (!glbind_SetPixelFormat(glbind_DC, glbind_PixelFormat, &glbind_PFD)) {
756 | DestroyWindow(hWnd);
757 | glbUnloadOpenGLSO();
758 | return GL_INVALID_OPERATION;
759 | }
760 |
761 | glbind_RC = glbind_wglCreateContext(glbind_DC);
762 | if (glbind_RC == NULL) {
763 | DestroyWindow(hWnd);
764 | glbUnloadOpenGLSO();
765 | return GL_INVALID_OPERATION;
766 | }
767 |
768 | glbind_wglMakeCurrent(glbind_DC, glbind_RC);
769 | }
770 | #endif
771 |
772 | #if defined(GLBIND_GLX)
773 | {
774 | static int attribs[] = {
775 | GLX_RGBA,
776 | GLX_RED_SIZE, 8,
777 | GLX_GREEN_SIZE, 8,
778 | GLX_BLUE_SIZE, 8,
779 | GLX_ALPHA_SIZE, 8,
780 | GLX_DEPTH_SIZE, 24,
781 | GLX_STENCIL_SIZE, 8,
782 | GLX_DOUBLEBUFFER,
783 | glbind_None, glbind_None
784 | };
785 |
786 | if (pConfig != NULL) {
787 | if (!pConfig->singleBuffered) {
788 | attribs[13] = glbind_None;
789 | }
790 | }
791 |
792 | glbind_OwnsDisplay = GL_TRUE;
793 | glbind_pDisplay = glbind_XOpenDisplay(NULL);
794 | if (glbind_pDisplay == NULL) {
795 | glbUnloadOpenGLSO();
796 | return GL_INVALID_OPERATION;
797 | }
798 |
799 | glbind_pFBVisualInfo = glbind_glXChooseVisual(glbind_pDisplay, glbind_XDefaultScreen(glbind_pDisplay), attribs);
800 | if (glbind_pFBVisualInfo == NULL) {
801 | glbUnloadOpenGLSO();
802 | return GL_INVALID_OPERATION;
803 | }
804 |
805 | glbind_DummyColormap = glbind_XCreateColormap(glbind_pDisplay, glbind_XRootWindow(glbind_pDisplay, glbind_pFBVisualInfo->screen), glbind_pFBVisualInfo->visual, glbind_AllocNone);
806 |
807 | glbind_RC = glbind_glXCreateContext(glbind_pDisplay, glbind_pFBVisualInfo, NULL, GL_TRUE);
808 | if (glbind_RC == NULL) {
809 | glbUnloadOpenGLSO();
810 | return GL_INVALID_OPERATION;
811 | }
812 |
813 | /* We cannot call any OpenGL APIs until a context is made current. In order to make a context current we will need a window. We just use a dummy window for this. */
814 | glbind_XSetWindowAttributes wa;
815 | wa.colormap = glbind_DummyColormap;
816 | wa.border_pixel = 0;
817 |
818 | /* Window's can not have dimensions of 0 in X11. We stick with dimensions of 1. */
819 | glbind_DummyWindow = glbind_XCreateWindow(glbind_pDisplay, glbind_XRootWindow(glbind_pDisplay, glbind_pFBVisualInfo->screen), 0, 0, 1, 1, 0, glbind_pFBVisualInfo->depth, glbind_InputOutput, glbind_pFBVisualInfo->visual, glbind_CWBorderPixel | glbind_CWColormap, &wa);
820 | if (glbind_DummyWindow == 0) {
821 | glbUnloadOpenGLSO();
822 | return GL_INVALID_OPERATION;
823 | }
824 |
825 | glbind_glXMakeCurrent(glbind_pDisplay, glbind_DummyWindow, glbind_RC);
826 | }
827 | #endif
828 | }
829 |
830 | if (pAPI != NULL) {
831 | #if defined(GLBIND_WGL)
832 | result = glbInitContextAPI(glbind_DC, glbind_RC, pAPI);
833 | #endif
834 | #if defined(GLBIND_GLX)
835 | result = glbInitContextAPI(glbind_pDisplay, glbind_DummyWindow, glbind_RC, pAPI);
836 | #endif
837 | if (result == GL_NO_ERROR) {
838 | if (g_glbInitCount == 0) {
839 | result = glbBindAPI(pAPI);
840 | }
841 | }
842 | } else {
843 | GLBapi tempAPI;
844 | #if defined(GLBIND_WGL)
845 | result = glbInitContextAPI(glbind_DC, glbind_RC, &tempAPI);
846 | #endif
847 | #if defined(GLBIND_GLX)
848 | result = glbInitContextAPI(glbind_pDisplay, glbind_DummyWindow, glbind_RC, &tempAPI);
849 | #endif
850 | if (result == GL_NO_ERROR) {
851 | if (g_glbInitCount == 0) {
852 | result = glbBindAPI(pAPI);
853 | }
854 | }
855 | }
856 |
857 | /* If at this point we have an error we need to uninitialize the global objects (if this is the initial initialization) and return. */
858 | if (result != GL_NO_ERROR) {
859 | if (g_glbInitCount == 0) {
860 | #if defined(GLBIND_WGL)
861 | if (glbind_RC) {
862 | glbind_wglDeleteContext(glbind_RC);
863 | glbind_RC = 0;
864 | }
865 | if (glbind_DummyHWND) {
866 | DestroyWindow(glbind_DummyHWND);
867 | glbind_DummyHWND = 0;
868 | }
869 | glbind_DC = 0;
870 | #endif
871 | #if defined(GLBIND_GLX)
872 | if (glbind_RC) {
873 | glbind_glXDestroyContext(glbind_pDisplay, glbind_RC);
874 | glbind_RC = 0;
875 | }
876 | if (glbind_DummyWindow) {
877 | glbind_XDestroyWindow(glbind_pDisplay, glbind_DummyWindow);
878 | glbind_DummyWindow = 0;
879 | }
880 | if (glbind_pDisplay && glbind_OwnsDisplay) {
881 | glbind_XCloseDisplay(glbind_pDisplay);
882 | glbind_pDisplay = 0;
883 | glbind_OwnsDisplay = GL_FALSE;
884 | }
885 | #endif
886 |
887 | glbUnloadOpenGLSO();
888 | }
889 |
890 | return result;
891 | }
892 |
893 | g_glbInitCount += 1; /* <-- Only increment the init counter on success. */
894 | return GL_NO_ERROR;
895 | }
896 |
897 | #if defined(GLBIND_WGL)
898 | GLenum glbInitContextAPI(HDC dc, HGLRC rc, GLBapi* pAPI)
899 | {
900 | GLenum result;
901 | HDC dcPrev;
902 | HGLRC rcPrev;
903 |
904 | dcPrev = glbind_wglGetCurrentDC();
905 | rcPrev = glbind_wglGetCurrentContext();
906 |
907 | if (dcPrev != dc && rcPrev != rc) {
908 | glbind_wglMakeCurrent(dc, rc);
909 | }
910 |
911 | result = glbInitCurrentContextAPI(pAPI);
912 |
913 | if (dcPrev != dc && rcPrev != rc) {
914 | glbind_wglMakeCurrent(dcPrev, rcPrev);
915 | }
916 |
917 | return result;
918 | }
919 | #endif
920 | #if defined(GLBIND_GLX)
921 | GLenum glbInitContextAPI(Display *dpy, GLXDrawable drawable, GLXContext rc, GLBapi* pAPI)
922 | {
923 | GLenum result;
924 | GLXContext rcPrev = 0;
925 | GLXDrawable drawablePrev = 0;
926 | glbind_Display* dpyPrev = NULL;
927 |
928 | if (glbind_glXGetCurrentContext && glbind_glXGetCurrentDrawable && glbind_glXGetCurrentDisplay) {
929 | rcPrev = glbind_glXGetCurrentContext();
930 | drawablePrev = glbind_glXGetCurrentDrawable();
931 | dpyPrev = glbind_glXGetCurrentDisplay();
932 | }
933 |
934 | glbind_glXMakeCurrent(dpy, drawable, rc);
935 | result = glbInitCurrentContextAPI(pAPI);
936 | glbind_glXMakeCurrent(dpyPrev, drawablePrev, rcPrev);
937 |
938 | return result;
939 | }
940 | #endif
941 |
942 | GLenum glbInitCurrentContextAPI(GLBapi* pAPI)
943 | {
944 | if (pAPI == NULL) {
945 | return GL_INVALID_OPERATION;
946 | }
947 |
948 | glbZeroObject(pAPI);
949 |
950 | /*<>*/
951 |
952 | return GL_NO_ERROR;
953 | }
954 |
955 | void glbUninit(void)
956 | {
957 | if (g_glbInitCount == 0) {
958 | return;
959 | }
960 |
961 | g_glbInitCount -= 1;
962 | if (g_glbInitCount == 0) {
963 | #if defined(GLBIND_WGL)
964 | if (glbind_RC) {
965 | glbind_wglDeleteContext(glbind_RC);
966 | glbind_RC = 0;
967 | }
968 | if (glbind_DummyHWND) {
969 | DestroyWindow(glbind_DummyHWND);
970 | glbind_DummyHWND = 0;
971 | }
972 | glbind_DC = 0;
973 | #endif
974 | #if defined(GLBIND_GLX)
975 | if (glbind_RC) {
976 | glbind_glXDestroyContext(glbind_pDisplay, glbind_RC);
977 | glbind_RC = 0;
978 | }
979 | if (glbind_DummyWindow) {
980 | glbind_XDestroyWindow(glbind_pDisplay, glbind_DummyWindow);
981 | glbind_DummyWindow = 0;
982 | }
983 | if (glbind_pDisplay && glbind_OwnsDisplay) {
984 | glbind_XCloseDisplay(glbind_pDisplay);
985 | glbind_pDisplay = 0;
986 | glbind_OwnsDisplay = GL_FALSE;
987 | }
988 | #endif
989 |
990 | glb_dlclose(g_glbOpenGLSO);
991 | g_glbOpenGLSO = NULL;
992 | }
993 | }
994 |
995 | GLenum glbBindAPI(const GLBapi* pAPI)
996 | {
997 | GLenum result;
998 |
999 | if (pAPI == NULL) {
1000 | GLBapi tempAPI;
1001 | #if defined(GLBIND_WGL)
1002 | result = glbInitContextAPI(glbind_DC, glbind_RC, &tempAPI);
1003 | #endif
1004 | #if defined(GLBIND_GLX)
1005 | result = glbInitContextAPI(glbind_pDisplay, glbind_DummyWindow, glbind_RC, &tempAPI);
1006 | #endif
1007 | if (result != GL_NO_ERROR) {
1008 | return result;
1009 | }
1010 |
1011 | return glbBindAPI(&tempAPI);
1012 | }
1013 |
1014 | /*<>*/
1015 |
1016 | return GL_NO_ERROR;
1017 | }
1018 |
1019 | #if defined(GLBIND_WGL)
1020 | HGLRC glbGetRC(void)
1021 | {
1022 | return glbind_RC;
1023 | }
1024 |
1025 | HDC glbGetDC(void)
1026 | {
1027 | return glbind_DC;
1028 | }
1029 |
1030 | int glbGetPixelFormat(void)
1031 | {
1032 | return glbind_PixelFormat;
1033 | }
1034 |
1035 | PIXELFORMATDESCRIPTOR* glbGetPFD(void)
1036 | {
1037 | return &glbind_PFD;
1038 | }
1039 | #endif
1040 |
1041 | #if defined(GLBIND_GLX)
1042 | glbind_Display* glbGetDisplay(void)
1043 | {
1044 | return glbind_pDisplay;
1045 | }
1046 |
1047 | GLXContext glbGetRC(void)
1048 | {
1049 | return glbind_RC;
1050 | }
1051 |
1052 | Colormap glbGetColormap(void)
1053 | {
1054 | return glbind_DummyColormap;
1055 | }
1056 |
1057 | XVisualInfo* glbGetFBVisualInfo(void)
1058 | {
1059 | return glbind_pFBVisualInfo;
1060 | }
1061 | #endif
1062 |
1063 |
1064 | int glb_strcmp(const char* s1, const char* s2)
1065 | {
1066 | while ((*s1) && (*s1 == *s2)) {
1067 | ++s1;
1068 | ++s2;
1069 | }
1070 |
1071 | return (*(unsigned char*)s1 - *(unsigned char*)s2);
1072 | }
1073 |
1074 | int glb_strncmp(const char* s1, const char* s2, size_t n)
1075 | {
1076 | while (n && *s1 && (*s1 == *s2)) {
1077 | ++s1;
1078 | ++s2;
1079 | --n;
1080 | }
1081 |
1082 | if (n == 0) {
1083 | return 0;
1084 | } else {
1085 | return (*(unsigned char*)s1 - *(unsigned char*)s2);
1086 | }
1087 | }
1088 |
1089 | GLboolean glbIsExtensionInString(const char* ext, const char* str)
1090 | {
1091 | const char* ext2beg;
1092 | const char* ext2end;
1093 |
1094 | if (ext == NULL || str == NULL) {
1095 | return GL_FALSE;
1096 | }
1097 |
1098 | ext2beg = str;
1099 | ext2end = ext2beg;
1100 |
1101 | for (;;) {
1102 | while (ext2end[0] != ' ' && ext2end[0] != '\0') {
1103 | ext2end += 1;
1104 | }
1105 |
1106 | if (glb_strncmp(ext, ext2beg, ext2end - ext2beg) == 0) {
1107 | return GL_TRUE;
1108 | }
1109 |
1110 | /* Break if we've reached the end. Otherwise, just move to start fo the next extension. */
1111 | if (ext2end[0] == '\0') {
1112 | break;
1113 | } else {
1114 | ext2beg = ext2end + 1;
1115 | ext2end = ext2beg;
1116 | }
1117 | }
1118 |
1119 | return GL_FALSE;
1120 | }
1121 |
1122 | #if defined(GLBIND_WGL)
1123 | GLboolean glbIsExtensionSupportedWGL(GLBapi* pAPI, const char* extensionName)
1124 | {
1125 | PFNWGLGETEXTENSIONSSTRINGARBPROC _wglGetExtensionsStringARB = (pAPI != NULL) ? pAPI->wglGetExtensionsStringARB : wglGetExtensionsStringARB;
1126 | PFNWGLGETEXTENSIONSSTRINGEXTPROC _wglGetExtensionsStringEXT = (pAPI != NULL) ? pAPI->wglGetExtensionsStringEXT : wglGetExtensionsStringEXT;
1127 | PFNWGLGETCURRENTDCPROC _wglGetCurrentDC = (pAPI != NULL) ? pAPI->wglGetCurrentDC : glbind_wglGetCurrentDC;
1128 |
1129 | if (_wglGetExtensionsStringARB) {
1130 | return glbIsExtensionInString(extensionName, _wglGetExtensionsStringARB(_wglGetCurrentDC()));
1131 | }
1132 | if (_wglGetExtensionsStringEXT) {
1133 | return glbIsExtensionInString(extensionName, _wglGetExtensionsStringEXT());
1134 | }
1135 |
1136 | return GL_FALSE;
1137 | }
1138 | #endif
1139 |
1140 | #if defined(GLBIND_GLX)
1141 | GLboolean glbIsExtensionSupportedGLX(GLBapi* pAPI, const char* extensionName)
1142 | {
1143 | PFNGLXQUERYEXTENSIONSSTRINGPROC _glXQueryExtensionsString = (pAPI != NULL) ? pAPI->glXQueryExtensionsString : glbind_glXQueryExtensionsString;
1144 |
1145 | if (_glXQueryExtensionsString) {
1146 | return glbIsExtensionInString(extensionName, _glXQueryExtensionsString(glbGetDisplay(), glbind_XDefaultScreen(glbGetDisplay())));
1147 | }
1148 |
1149 | return GL_FALSE;
1150 | }
1151 | #endif
1152 |
1153 | GLboolean glbIsExtensionSupported(GLBapi* pAPI, const char* extensionName)
1154 | {
1155 | GLboolean isSupported = GL_FALSE;
1156 | PFNGLGETSTRINGIPROC _glGetStringi = (pAPI != NULL) ? pAPI->glGetStringi : glGetStringi;
1157 | PFNGLGETSTRINGPROC _glGetString = (pAPI != NULL) ? pAPI->glGetString : glGetString;
1158 | PFNGLGETINTEGERVPROC _glGetIntegerv = (pAPI != NULL) ? pAPI->glGetIntegerv : glGetIntegerv;
1159 |
1160 | /* Try the new way first. */
1161 | if (_glGetStringi && _glGetIntegerv) {
1162 | GLint iExtension;
1163 | GLint supportedExtensionCount = 0;
1164 | _glGetIntegerv(GL_NUM_EXTENSIONS, &supportedExtensionCount);
1165 |
1166 | for (iExtension = 0; iExtension < supportedExtensionCount; ++iExtension) {
1167 | const char* pSupportedExtension = (const char*)_glGetStringi(GL_EXTENSIONS, iExtension);
1168 | if (pSupportedExtension != NULL) {
1169 | if (glb_strcmp(pSupportedExtension, extensionName) == 0) {
1170 | return GL_TRUE;
1171 | }
1172 | }
1173 | }
1174 |
1175 | /* It's not a core extension. Check platform-specific extensions. */
1176 | isSupported = GL_FALSE;
1177 | #if defined(GLBIND_WGL)
1178 | isSupported = glbIsExtensionSupportedWGL(pAPI, extensionName);
1179 | #endif
1180 | #if defined(GLBIND_GLX)
1181 | isSupported = glbIsExtensionSupportedGLX(pAPI, extensionName);
1182 | #endif
1183 | return isSupported;
1184 | }
1185 |
1186 | /* Fall back to old style. */
1187 | if (_glGetString) {
1188 | isSupported = glbIsExtensionInString(extensionName, (const char*)_glGetString(GL_EXTENSIONS));
1189 | if (!isSupported) {
1190 | #if defined(GLBIND_WGL)
1191 | isSupported = glbIsExtensionSupportedWGL(pAPI, extensionName);
1192 | #endif
1193 | #if defined(GLBIND_GLX)
1194 | isSupported = glbIsExtensionSupportedGLX(pAPI, extensionName);
1195 | #endif
1196 | }
1197 | }
1198 |
1199 | return isSupported;
1200 | }
1201 |
1202 | #endif /* GLBIND_IMPLEMENTATION */
1203 |
1204 | /*
1205 | This software is available as a choice of the following licenses. Choose
1206 | whichever you prefer.
1207 |
1208 | ===============================================================================
1209 | ALTERNATIVE 1 - Public Domain (www.unlicense.org)
1210 | ===============================================================================
1211 | This is free and unencumbered software released into the public domain.
1212 |
1213 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
1214 | software, either in source code form or as a compiled binary, for any purpose,
1215 | commercial or non-commercial, and by any means.
1216 |
1217 | In jurisdictions that recognize copyright laws, the author or authors of this
1218 | software dedicate any and all copyright interest in the software to the public
1219 | domain. We make this dedication for the benefit of the public at large and to
1220 | the detriment of our heirs and successors. We intend this dedication to be an
1221 | overt act of relinquishment in perpetuity of all present and future rights to
1222 | this software under copyright law.
1223 |
1224 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1225 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1226 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1227 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1228 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1229 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1230 |
1231 | For more information, please refer to
1232 |
1233 | ===============================================================================
1234 | ALTERNATIVE 2 - MIT No Attribution
1235 | ===============================================================================
1236 | Copyright 2019 David Reid
1237 |
1238 | Permission is hereby granted, free of charge, to any person obtaining a copy of
1239 | this software and associated documentation files (the "Software"), to deal in
1240 | the Software without restriction, including without limitation the rights to
1241 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1242 | of the Software, and to permit persons to whom the Software is furnished to do
1243 | so.
1244 |
1245 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1246 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1247 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1248 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1249 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1250 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1251 | SOFTWARE.
1252 | */
1253 |
--------------------------------------------------------------------------------