[852] | 1 | // Comments:
|
---|
| 2 | //
|
---|
| 3 | // The trick with GLH_EXT_SINGLE_FILE is that you need to have it defined in
|
---|
| 4 | // exactly one cpp file because it piggy-backs the function implementations in
|
---|
| 5 | // the header. You don't want multiple implementations defined or the linker
|
---|
| 6 | // gets mad, but one file must have the implementations in it or the linker
|
---|
| 7 | // gets mad for different reasons.
|
---|
| 8 | //
|
---|
| 9 | // The goal was to avoid having this helper require a separate cpp file. One
|
---|
| 10 | // thing you could do is just have a glh_extensions.cpp that did
|
---|
| 11 | //
|
---|
| 12 | // #define GLH_EXT_SINGLE_FILE
|
---|
| 13 | // #include <glh_extensions.h>
|
---|
| 14 | //
|
---|
| 15 | // and make it the only file that ever defines GLH_EXT_SINGLE_FILE.
|
---|
| 16 |
|
---|
| 17 | #ifndef GLH_EXTENSIONS
|
---|
| 18 | #define GLH_EXTENSIONS
|
---|
| 19 |
|
---|
| 20 | #include <string.h>
|
---|
| 21 | #include <stdio.h>
|
---|
| 22 | #include <stdlib.h>
|
---|
| 23 |
|
---|
| 24 | #if defined(WIN32)
|
---|
| 25 | # include <windows.h>
|
---|
| 26 | #endif
|
---|
| 27 |
|
---|
| 28 | #ifdef MACOS
|
---|
| 29 | #include <OpenGL/gl.h>
|
---|
| 30 | #else
|
---|
| 31 | #include <GL/gl.h>
|
---|
| 32 | #endif
|
---|
| 33 |
|
---|
| 34 | #ifdef WIN32
|
---|
| 35 | # include <GL/wglext.h>
|
---|
| 36 | #endif
|
---|
| 37 |
|
---|
| 38 | #define CHECK_MEMORY(ptr) \
|
---|
| 39 | if (NULL == ptr) { \
|
---|
| 40 | printf("Error allocating memory in file %s, line %d\n", __FILE__, __LINE__); \
|
---|
| 41 | exit(-1); \
|
---|
| 42 | }
|
---|
| 43 |
|
---|
| 44 | #ifdef GLH_EXT_SINGLE_FILE
|
---|
| 45 | # define GLH_EXTENSIONS_SINGLE_FILE // have to do this because glh_genext.h unsets GLH_EXT_SINGLE_FILE
|
---|
| 46 | #endif
|
---|
| 47 |
|
---|
| 48 | #if (defined(WIN32) || defined(UNIX))
|
---|
| 49 | #include "glh_genext.h"
|
---|
| 50 | #elif defined(MACOS)
|
---|
| 51 | #include <OpenGL/glext.h>
|
---|
| 52 | #else
|
---|
| 53 | #include <GL/glext.h>
|
---|
| 54 | #endif
|
---|
| 55 |
|
---|
| 56 | #ifdef __cplusplus
|
---|
| 57 | extern "C" {
|
---|
| 58 | #endif
|
---|
| 59 |
|
---|
| 60 | #ifdef GLH_EXTENSIONS_SINGLE_FILE
|
---|
| 61 | static char *unsupportedExts = NULL;
|
---|
| 62 | static char *sysExts = NULL;
|
---|
| 63 | #ifndef GL_SHADER_CONSISTENT_NV
|
---|
| 64 | #define GL_SHADER_CONSISTENT_NV 0x86DD
|
---|
| 65 | #endif
|
---|
| 66 | #ifndef GL_TEXTURE_SHADER_NV
|
---|
| 67 | #define GL_TEXTURE_SHADER_NV 0x86DE
|
---|
| 68 | #endif
|
---|
| 69 | #ifndef GL_SHADER_OPERATION_NV
|
---|
| 70 | #define GL_SHADER_OPERATION_NV 0x86DF
|
---|
| 71 | #endif
|
---|
| 72 |
|
---|
| 73 | static int ExtensionExists(const char* extName, const char* sysExts)
|
---|
| 74 | {
|
---|
| 75 | char *padExtName = (char*)malloc(strlen(extName) + 2);
|
---|
| 76 | strcat(strcpy(padExtName, extName), " ");
|
---|
| 77 |
|
---|
| 78 | if (0 == strcmp(extName, "GL_VERSION_1_2")) {
|
---|
| 79 | const char *version = (const char*)glGetString(GL_VERSION);
|
---|
| 80 | if (strstr(version, "1.0") == version || strstr(version, "1.1") == version) {
|
---|
| 81 | return GL_FALSE;
|
---|
| 82 | } else {
|
---|
| 83 | return GL_TRUE;
|
---|
| 84 | }
|
---|
| 85 | }
|
---|
| 86 | if (0 == strcmp(extName, "GL_VERSION_1_3")) {
|
---|
| 87 | const char *version = (const char*)glGetString(GL_VERSION);
|
---|
| 88 | if (strstr(version, "1.0") == version ||
|
---|
| 89 | strstr(version, "1.1") == version ||
|
---|
| 90 | strstr(version, "1.2") == version) {
|
---|
| 91 | return GL_FALSE;
|
---|
| 92 | } else {
|
---|
| 93 | return GL_TRUE;
|
---|
| 94 | }
|
---|
| 95 | }
|
---|
| 96 | if (0 == strcmp(extName, "GL_VERSION_1_4")) {
|
---|
| 97 | const char *version = (const char*)glGetString(GL_VERSION);
|
---|
| 98 | if (strstr(version, "1.0") == version ||
|
---|
| 99 | strstr(version, "1.1") == version ||
|
---|
| 100 | strstr(version, "1.2") == version ||
|
---|
| 101 | strstr(version, "1.3") == version) {
|
---|
| 102 | return GL_FALSE;
|
---|
| 103 | } else {
|
---|
| 104 | return GL_TRUE;
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 | if (0 == strcmp(extName, "GL_VERSION_1_5")) {
|
---|
| 108 | const char *version = (const char*)glGetString(GL_VERSION);
|
---|
| 109 | if (strstr(version, "1.0") == version ||
|
---|
| 110 | strstr(version, "1.1") == version ||
|
---|
| 111 | strstr(version, "1.2") == version ||
|
---|
| 112 | strstr(version, "1.3") == version ||
|
---|
| 113 | strstr(version, "1.4") == version) {
|
---|
| 114 | return GL_FALSE;
|
---|
| 115 | } else {
|
---|
| 116 | return GL_TRUE;
|
---|
| 117 | }
|
---|
| 118 | }
|
---|
| 119 | if (strstr(sysExts, padExtName)) {
|
---|
| 120 | free(padExtName);
|
---|
| 121 | return GL_TRUE;
|
---|
| 122 | } else {
|
---|
| 123 | free(padExtName);
|
---|
| 124 | return GL_FALSE;
|
---|
| 125 | }
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | static const char* EatWhiteSpace(const char *str)
|
---|
| 129 | {
|
---|
| 130 | for (; *str && (' ' == *str || '\t' == *str || '\n' == *str); str++);
|
---|
| 131 | return str;
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | static const char* EatNonWhiteSpace(const char *str)
|
---|
| 135 | {
|
---|
| 136 | for (; *str && (' ' != *str && '\t' != *str && '\n' != *str); str++);
|
---|
| 137 | return str;
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | int glh_init_extensions(const char *origReqExts)
|
---|
| 141 | {
|
---|
| 142 | // Length of requested extensions string
|
---|
| 143 | size_t reqExtsLen;
|
---|
| 144 | char *reqExts;
|
---|
| 145 | // Ptr for individual extensions within reqExts
|
---|
| 146 | char *reqExt;
|
---|
| 147 | int success = GL_TRUE;
|
---|
| 148 | // build space-padded extension string
|
---|
| 149 | if (NULL == sysExts) {
|
---|
| 150 | const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
|
---|
| 151 | size_t sysExtsLen = strlen(extensions);
|
---|
| 152 | const char *winsys_extensions = "";
|
---|
| 153 | size_t winsysExtsLen = 0;
|
---|
| 154 | #if defined(WIN32)
|
---|
| 155 | {
|
---|
| 156 | PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
|
---|
| 157 | wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
|
---|
| 158 | if(wglGetExtensionsStringARB)
|
---|
| 159 | {
|
---|
| 160 | winsys_extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
|
---|
| 161 | winsysExtsLen = strlen(winsys_extensions);
|
---|
| 162 | }
|
---|
| 163 | }
|
---|
| 164 | #elif defined(UNIX)
|
---|
| 165 | {
|
---|
| 166 |
|
---|
| 167 | winsys_extensions = glXQueryExtensionsString (glXGetCurrentDisplay(),DefaultScreen(glXGetCurrentDisplay())) ;
|
---|
| 168 | winsysExtsLen = strlen (winsys_extensions);
|
---|
| 169 | }
|
---|
| 170 | #endif
|
---|
| 171 | // Add 2 bytes, one for padding space, one for terminating NULL
|
---|
| 172 | sysExts = (char*)malloc(sysExtsLen + winsysExtsLen + 3);
|
---|
| 173 | CHECK_MEMORY(sysExts);
|
---|
| 174 | strcpy(sysExts, extensions);
|
---|
| 175 | sysExts[sysExtsLen] = ' ';
|
---|
| 176 | sysExts[sysExtsLen + 1] = 0;
|
---|
| 177 | strcat(sysExts, winsys_extensions);
|
---|
| 178 | sysExts[sysExtsLen + 1 + winsysExtsLen] = ' ';
|
---|
| 179 | sysExts[sysExtsLen + 1 + winsysExtsLen + 1] = 0;
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | if (NULL == origReqExts)
|
---|
| 183 | return GL_TRUE;
|
---|
| 184 | reqExts = strdup(origReqExts);
|
---|
| 185 | reqExtsLen = strlen(reqExts);
|
---|
| 186 | if (NULL == unsupportedExts) {
|
---|
| 187 | unsupportedExts = (char*)malloc(reqExtsLen + 2);
|
---|
| 188 | } else if (reqExtsLen > strlen(unsupportedExts)) {
|
---|
| 189 | unsupportedExts = (char*)realloc(unsupportedExts, reqExtsLen + 2);
|
---|
| 190 | }
|
---|
| 191 | CHECK_MEMORY(unsupportedExts);
|
---|
| 192 | *unsupportedExts = 0;
|
---|
| 193 |
|
---|
| 194 | // Parse requested extension list
|
---|
| 195 | for (reqExt = reqExts;
|
---|
| 196 | (reqExt = (char*)EatWhiteSpace(reqExt)) && *reqExt;
|
---|
| 197 | reqExt = (char*)EatNonWhiteSpace(reqExt))
|
---|
| 198 | {
|
---|
| 199 | char *extEnd = (char*)EatNonWhiteSpace(reqExt);
|
---|
| 200 | char saveChar = *extEnd;
|
---|
| 201 | *extEnd = (char)0;
|
---|
| 202 |
|
---|
| 203 | #if (defined(WIN32) || defined(UNIX))
|
---|
| 204 | if (!ExtensionExists(reqExt, sysExts) || !glh_init_extension(reqExt)) {
|
---|
| 205 | #elif defined(MACOS)
|
---|
| 206 | if (!ExtensionExists(reqExt, sysExts)) { // don't try to get function pointers if on MacOS
|
---|
| 207 | #endif
|
---|
| 208 | // add reqExt to end of unsupportedExts
|
---|
| 209 | strcat(unsupportedExts, reqExt);
|
---|
| 210 | strcat(unsupportedExts, " ");
|
---|
| 211 | success = GL_FALSE;
|
---|
| 212 | }
|
---|
| 213 | *extEnd = saveChar;
|
---|
| 214 | }
|
---|
| 215 | free(reqExts);
|
---|
| 216 | return success;
|
---|
| 217 | }
|
---|
| 218 |
|
---|
| 219 | const char* glh_get_unsupported_extensions()
|
---|
| 220 | {
|
---|
| 221 | return (const char*)unsupportedExts;
|
---|
| 222 | }
|
---|
| 223 |
|
---|
| 224 | void glh_shutdown_extensions()
|
---|
| 225 | {
|
---|
| 226 | if (unsupportedExts)
|
---|
| 227 | {
|
---|
| 228 | free(unsupportedExts);
|
---|
| 229 | unsupportedExts = NULL;
|
---|
| 230 | }
|
---|
| 231 | if (sysExts)
|
---|
| 232 | {
|
---|
| 233 | free(sysExts);
|
---|
| 234 | sysExts = NULL;
|
---|
| 235 | }
|
---|
| 236 | }
|
---|
| 237 |
|
---|
| 238 | int glh_extension_supported(const char *extension)
|
---|
| 239 | {
|
---|
| 240 | static const GLubyte *extensions = NULL;
|
---|
| 241 | const GLubyte *start;
|
---|
| 242 | GLubyte *where, *terminator;
|
---|
| 243 |
|
---|
| 244 | // Extension names should not have spaces.
|
---|
| 245 | where = (GLubyte *) strchr(extension, ' ');
|
---|
| 246 | if (where || *extension == '\0')
|
---|
| 247 | return 0;
|
---|
| 248 |
|
---|
| 249 | if (!extensions)
|
---|
| 250 | extensions = glGetString(GL_EXTENSIONS);
|
---|
| 251 |
|
---|
| 252 | // It takes a bit of care to be fool-proof about parsing the
|
---|
| 253 | // OpenGL extensions string. Don't be fooled by sub-strings,
|
---|
| 254 | // etc.
|
---|
| 255 | start = extensions;
|
---|
| 256 | for (;;)
|
---|
| 257 | {
|
---|
| 258 | where = (GLubyte *) strstr((const char *) start, extension);
|
---|
| 259 | if (!where)
|
---|
| 260 | break;
|
---|
| 261 | terminator = where + strlen(extension);
|
---|
| 262 | if (where == start || *(where - 1) == ' ')
|
---|
| 263 | {
|
---|
| 264 | if (*terminator == ' ' || *terminator == '\0')
|
---|
| 265 | {
|
---|
| 266 | return 1;
|
---|
| 267 | }
|
---|
| 268 | }
|
---|
| 269 | start = terminator;
|
---|
| 270 | }
|
---|
| 271 | return 0;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 | #else
|
---|
| 275 | int glh_init_extensions(const char *origReqExts);
|
---|
| 276 | const char* glh_get_unsupported_extensions();
|
---|
| 277 | void glh_shutdown_extensions();
|
---|
| 278 | int glh_extension_supported(const char *extension);
|
---|
| 279 | #endif /* GLH_EXT_SINGLE_FILE */
|
---|
| 280 |
|
---|
| 281 | #ifdef __cplusplus
|
---|
| 282 | }
|
---|
| 283 | #endif
|
---|
| 284 |
|
---|
| 285 | #endif /* GLH_EXTENSIONS */
|
---|