├── .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 | discord 5 | mastodon 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 | --------------------------------------------------------------------------------