commit 94f4142716079ac1bdcb91a2b8098610a84d59db parent f380d958b40b29bfb0fd3ade7636eba57909e62a Author: Michael Savage <mikejsavage@gmail.com> Date: Sun Dec 25 17:37:56 +0200 Add libs/glad and scripts/glad.sh Diffstat:
libs/glad/.gitignore | | | 1 | + |
libs/glad/LICENSE | | | 20 | ++++++++++++++++++++ |
libs/glad/README.md | | | 285 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/__init__.py | | | 3 | +++ |
libs/glad/glad/__main__.py | | | 160 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/__init__.py | | | 19 | +++++++++++++++++++ |
libs/glad/glad/lang/c/__init__.py | | | 28 | ++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/debug.py | | | 116 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/generator.py | | | 291 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/loader/__init__.py | | | 132 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/loader/egl.py | | | 84 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/loader/gl.py | | | 242 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/loader/glx.py | | | 148 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/c/loader/wgl.py | | | 142 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/common/__init__.py | | | 0 | |
libs/glad/glad/lang/common/generator.py | | | 242 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/common/loader.py | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/common/util.py | | | 14 | ++++++++++++++ |
libs/glad/glad/lang/d/__init__.py | | | 25 | +++++++++++++++++++++++++ |
libs/glad/glad/lang/d/generator.py | | | 861 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/d/loader/__init__.py | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/d/loader/egl.py | | | 39 | +++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/d/loader/gl.py | | | 118 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/d/loader/glx.py | | | 49 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/d/loader/wgl.py | | | 36 | ++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/__init__.py | | | 27 | +++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/generator.py | | | 530 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/loader/__init__.py | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/loader/egl.py | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/loader/gl.py | | | 147 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/loader/glx.py | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/nim/loader/wgl.py | | | 38 | ++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/__init__.py | | | 25 | +++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/generator.py | | | 86 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/loader/__init__.py | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/loader/egl.py | | | 49 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/loader/gl.py | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/loader/glx.py | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/lang/volt/loader/wgl.py | | | 36 | ++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/opener.py | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/parse.py | | | 356 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/spec.py | | | 50 | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
libs/glad/glad/util.py | | | 14 | ++++++++++++++ |
libs/glad/main.py | | | 9 | +++++++++ |
scripts/glad.sh | | | 11 | +++++++++++ |
diff --git a/libs/glad/.gitignore b/libs/glad/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/libs/glad/LICENSE b/libs/glad/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 David Herberth + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libs/glad/README.md b/libs/glad/README.md @@ -0,0 +1,285 @@ +glad +==== + +GL/GLES/EGL/GLX/WGL Loader-Generator based on the official specs. + +Checkout the [webservice](http://glad.dav1d.de) to generate the files you need! + + +```c +// GLAD_DEBUG is only defined if the c-debug generator was used +#ifdef GLAD_DEBUG +// logs every gl call to the console +void pre_gl_call(const char *name, void *funcptr, int len_args, ...) { + printf("Calling: %s (%d arguments)\n", name, len_args); +} +#endif + + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); + glutInitWindowSize(width, height); + glutCreateWindow("cookie"); + + glutReshapeFunc(reshape); + glutDisplayFunc(display); + + if(!gladLoadGL()) { + printf("Something went wrong!\n"); + exit(-1); + } + +#ifdef GLAD_DEBUG + // before every opengl call call pre_gl_call + glad_set_pre_callback(pre_gl_call); + + // post callback checks for glGetError by default + + // don't use the callback for glClear + // (glClear could be replaced with your own function) + glad_debug_glClear = glad_glClear; +#endif + + // gladLoadGLLoader(&glutGetProcAddress); + printf("OpenGL %d.%d\n", GLVersion.major, GLVersion.minor); + if (GLVersion.major < 2) { + printf("Your system doesn't support OpenGL >= 2!\n"); + return -1; + } + + printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), + glGetString(GL_SHADING_LANGUAGE_VERSION)); + + glutMainLoop(); + + return 0; +} +``` + +Checkout the full example: [simple.c](https://github.com/Dav1dde/glad/blob/master/example/c/simple.c) + +Or the C++ example using [GLFW](http://glfw.org): +[hellowindow2.cpp](https://github.com/Dav1dde/glad/blob/master/example/c%2B%2B/hellowindow2.cpp) + + +## Usage ## + + +**If you don't want to install glad you can use the [webservice](http://glad.dav1d.de)** + + +Otherwise either install glad via pip: + + # Windows + pip install glad + + # Linux + pip install --user glad + # Linux global (root) + pip install glad + + glad --help + +To install the most recent version from Github: + + pip install --upgrade git+https://github.com/dav1dde/glad.git#egg=glad + +Or launch glad directly (after cloning the repository): + + python -m glad --help + + +Possible commandline options: + + usage: glad [-h] [--profile {core,compatibility}] --out-path OUT + [--api API] --generator {c,d,volt} + [--extensions EXTENSIONS] [--spec {gl,egl,glx,wgl}] + [--no-loader] + + Uses the official Khronos-XML specs to generate a GL/GLES/EGL/GLX/WGL Loader + made for your needs. Glad currently supports the languages C, D and Volt. + + optional arguments: + -h, --help show this help message and exit + --profile {core,compatibility} + OpenGL profile (defaults to compatibility) + --out-path OUT Output path for loader + --api API API type/version pairs, like "gl=3.2,gles=", no + version means latest + --generator {c,c-debug,d,volt} + Language to generate the binding for + --extensions EXTENSIONS + Path to extensions file or comma separated list of + extensions, if missing all extensions are included + --spec {gl,egl,glx,wgl} + Name of the spec + --no-loader + --omit-khrplatform Omits inclusion of the khrplatform.h file which is + often unnecessary. Only has an effect if used + together with c generators. + --local-files Forces every file directly into the output directory. + No src or include subdirectories are generated. Only + has an effect if used together with c generators. + + +To generate a loader for C with two extensions, it could look like this: + + python main.py --generator=c --extensions=GL_EXT_framebuffer_multisample,GL_EXT_texture_filter_anisotropic --out-path=GL + +`--out-path` and `--generator` are required! +If the `--extensions` option is missing, glad adds support for all extensions found in the OpenGL spec. + + +## Generators ## + +### C/C++ ### + +```c +struct gladGLversionStruct { + int major; + int minor; +}; + +extern struct gladGLversionStruct GLVersion; + +typedef void* (* GLADloadproc)(const char *name); + +/* + * Load OpenGL using the internal loader. + * Returns the true/1 if loading succeeded. + * + */ +int gladLoadGL(void); + +/* + * Load OpenGL using an external loader like SDL_GL_GetProcAddress. + * + * Substitute GL with the API you generated + * + */ +void gladLoadGLLoader(GLADloadproc); +``` + +`glad.h` completely replaces any `gl.h` or `gl3.h` only include `glad.h`. + +```c + if(!gladLoadGL()) { exit(-1) }; + printf("OpenGL Version %d.%d loaded", GLVersion.major, GLVersion.minor); + + if(GLAD_GL_EXT_framebuffer_multisample) { + /* GL_EXT_framebuffer_multisample is supported */ + } + + if(GLAD_GL_VERSION_3_0) { + /* We support at least OpenGL version 3 */ + } +``` + +On non-Windows platforms glad requires `libdl`, make sure to link with it (`-ldl` for gcc)! + +Note, there are two kinds of extension/version symbols, e.g. `GL_VERSION_3_0` and +`GLAD_VERSION_3_0`. Latter is a runtime boolean (represented as integer), whereas +the first (not prefixed with `GLAD_`) is a compiletime-constant, indicating that this +header supports this version (the official headers define these symbols as well). +The runtime booleans are only valid *after* a succesful call to `gladLoadGL` or `gladLoadGLLoader`. + + +### C/C++ Debug ### + +The C-Debug generator extends the API by these two functions: + +```c +// this symbol only exists if generated with the c-debug generator +#define GLAD_DEBUG +typedef void (* GLADcallback)(const char *name, void *funcptr, int len_args, ...); + +/* + * Sets a callback which will be called before every function call + * to a function loaded by glad. + * + */ +GLAPI void glad_set_pre_callback(GLADcallback cb); + +/* + * Sets a callback which will be called after every function call + * to a function loaded by glad. + * + */ +GLAPI void glad_set_post_callback(GLADcallback cb); +``` + +To call a function like `glGetError` in a callback prefix it with `glad_`, e.g. +the default post callback looks like this: + +```c +void _post_call_callback_default(const char *name, void *funcptr, int len_args, ...) { + GLenum error_code; + error_code = glad_glGetError(); + + if (error_code != GL_NO_ERROR) { + fprintf(stderr, "ERROR %d in %s\n", error_code, name); + } +} +``` + +You can also submit own implementations for every call made by overwriting +the function pointer with the name of the function prefixed by `glad_debug_`. + +E.g. you could disable the callbacks for glClear with `glad_debug_glClear = glad_glClear`, where +`glad_glClear` is the function pointer loaded by glad. + +The `glClear` macro is defined as `#define glClear glad_debug_glClear`, +`glad_debug_glClear` is initialized with a default implementation, which calls +the two callbacks and the real function, in this case `glad_glClear`. + + +### D ### + +Import `glad.gl` for OpenGL functions/extensions, import `glad.loader` to import +the functions needed to initialize glad and load the OpenGL functions. + +```d + enforce(gladLoadGL()); // optionally you can pass a loader to this function + writefln("OpenGL Version %d.%d loaded", GLVersion.major, GLVersion.minor); + + if(GL_EXT_framebuffer_multisample) { + /* GL_EXT_framebuffer_multisample is supported */ + } + + if(GL_VERSION_3_0) { + /* We support at least OpenGL version 3 */ + } +``` + +On non-Windows platforms glad requires `libdl`, make sure to link with it (`L-ldl` for dmd)! + + +## FAQ ## + +### glad includes windows.h which breaks my code! + +Defining `APIENTRY` before including `glad.h` solves this problem: + +```c +#ifdef _WIN32 + #define APIENTRY __stdcall +#endif + +#include <glad/glad.h> +``` + +But make sure you have the correct definition of `APIENTRY` for platforms which define `_WIN32` but don't use `__stdcall` + +Relevant issue: [#42](https://github.com/Dav1dde/glad/issues/42) + + + +## Contribute ## + +Contributing is easy! Found a bug? Message me or make a pull request! Added a new generator backend? +Make a pull request! + +Special thanks for all the people who contributed and are going to contribute! +Also to these who helped me solve a problem when I simply could not think of a solution. diff --git a/libs/glad/glad/__init__.py b/libs/glad/glad/__init__.py @@ -0,0 +1,3 @@ + +__version__ = '0.1.12a0' + diff --git a/libs/glad/glad/__main__.py b/libs/glad/glad/__main__.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python + +""" +Uses the official Khronos-XML specs to generate a +GL/GLES/EGL/GLX/WGL Loader made for your needs. Glad currently supports +the languages C, D, Nim and Volt. +""" +from collections import namedtuple +import logging +import sys + +from glad.opener import URLOpener +from glad.spec import SPECS +import glad.lang + + +Version = namedtuple('Version', ['major', 'minor']) + +logger = logging.getLogger('glad') + + +def main(): + import os.path + import argparse + from argparse import ArgumentParser + + opener = URLOpener() + + def get_spec(value): + if value not in SPECS: + raise argparse.ArgumentTypeError('Unknown specification') + + spec_cls = SPECS[value] + + if os.path.exists(value + '.xml'): + logger.info('using local specification: \'%s.xml\'', value) + return spec_cls.from_file(value + '.xml') + logger.info('getting \'%s\' specification from SVN', value) + return spec_cls.from_svn(opener=opener) + + def ext_file(value): + msg = 'Invalid extensions argument' + if os.path.exists(value): + msg = 'Invalid extensions file' + try: + with open(value, 'r') as f: + return f.read().split() + except IOError: + pass + else: + return [v.strip() for v in value.split(',') if v] + + raise argparse.ArgumentTypeError(msg) + + def version(value): + if value is None or len(value.strip()) == 0: + return None + + v = value + if '.' not in v: + v = '{}.0'.format(v) + + try: + return Version(*map(int, v.split('.'))) + except ValueError: + pass + + raise argparse.ArgumentTypeError('Invalid version: "{}"'.format(value)) + + def cmdapi(value): + try: + return dict((p[0], version(p[1])) for p in + (list(map(str.strip, e.split('='))) for e in + filter(bool, map(str.strip, value.split(','))))) + except IndexError: + pass + + raise argparse.ArgumentTypeError( + 'Invalid api-string: "{}"'.format(value) + ) + + description = __doc__ + parser = ArgumentParser(description=description) + + parser.add_argument('--profile', dest='profile', + choices=['core', 'compatibility'], + default='compatibility', + help='OpenGL profile (defaults to compatibility)') + parser.add_argument('--out-path', dest='out', required=True, + help='Output path for loader') + parser.add_argument('--api', dest='api', type=cmdapi, + help='API type/version pairs, like "gl=3.2,gles=", ' + 'no version means latest') + parser.add_argument('--generator', dest='generator', default='d', + choices=['c', 'c-debug', 'd', 'nim', 'volt'], required=True, + help='Language to generate the binding for') + parser.add_argument('--extensions', dest='extensions', + default=None, type=ext_file, + help='Path to extensions file or comma separated ' + 'list of extensions, if missing ' + 'all extensions are included') + parser.add_argument('--spec', dest='spec', default='gl', + choices=['gl', 'egl', 'glx', 'wgl'], + help='Name of the spec') + parser.add_argument('--no-loader', dest='no_loader', action='store_true') + parser.add_argument('--omit-khrplatform', dest='omit_khrplatform', action='store_true', + help='Omits inclusion of the khrplatform.h ' + 'file which is often unnecessary. ' + 'Only has an effect if used together ' + 'with c generators.') + parser.add_argument('--local-files', dest='local_files', action='store_true', + help='Forces every file directly into the output ' + 'directory. No src or include subdirectories ' + 'are generated. ' + 'Only has an effect if used together ' + 'with c generators.') + parser.add_argument('--quiet', dest='quiet', action='store_true') + + ns = parser.parse_args() + + if not ns.quiet: + logging.basicConfig( + format='[%(asctime)s][%(levelname)s\t][%(name)-7s\t]: %(message)s', + datefmt='%m/%d/%Y %H:%M:%S', level=logging.DEBUG + ) + + spec = get_spec(ns.spec) + if spec.NAME == 'gl': + spec.profile = ns.profile + + api = ns.api + if api is None or len(api.keys()) == 0: + api = {spec.NAME: None} + + generator_cls, loader_cls = glad.lang.get_generator( + ns.generator, spec.NAME.lower() + ) + + if loader_cls is None: + return parser.error('API/Spec not yet supported') + + loader = loader_cls(api, disabled=ns.no_loader, local_files=ns.local_files) + + logger.info('generating \'%s\' bindings', spec.NAME) + with generator_cls( + ns.out, + spec, + api, + ns.extensions, + loader=loader, + opener=opener, + local_files=ns.local_files, + omit_khrplatform=ns.omit_khrplatform + ) as generator: + generator.generate() + + logger.info('generating \'%s\' bindings - done', spec.NAME) + +if __name__ == '__main__': + main() diff --git a/libs/glad/glad/lang/__init__.py b/libs/glad/glad/lang/__init__.py @@ -0,0 +1,19 @@ +import glad.lang.c +import glad.lang.d +import glad.lang.nim +import glad.lang.volt + + +def get_generator(name, spec): + _langs = [ + glad.lang.c, + glad.lang.d, + glad.lang.nim, + glad.lang.volt + ] + + for lang in _langs: + gen, loader = lang.get_generator(name, spec) + if gen is not None: + return gen, loader + return None, None diff --git a/libs/glad/glad/lang/c/__init__.py b/libs/glad/glad/lang/c/__init__.py @@ -0,0 +1,28 @@ +from glad.lang.c.loader.egl import EGLCLoader +from glad.lang.c.loader.gl import OpenGLCLoader +from glad.lang.c.loader.glx import GLXCLoader +from glad.lang.c.loader.wgl import WGLCLoader + +from glad.lang.c.generator import CGenerator +from glad.lang.c.debug import CDebugGenerator + + +_specs = { + 'egl': EGLCLoader, + 'gl': OpenGLCLoader, + 'glx': GLXCLoader, + 'wgl': WGLCLoader +} + +_generators = { + 'c': CGenerator, + 'c-debug': CDebugGenerator +} + + +def get_generator(name, spec): + gen = _generators.get(name) + loader = _specs.get(spec) + + return gen, loader + diff --git a/libs/glad/glad/lang/c/debug.py b/libs/glad/glad/lang/c/debug.py @@ -0,0 +1,116 @@ +from glad.lang.c.generator import CGenerator + + +DEFAULT_DEBUG_IMPL = ''' + {return_def} + _pre_call_callback("{name}", {args_callback}); + {return_assign} glad_{name}({args}); + _post_call_callback("{name}", {args_callback}); + {return_return} +''' + + +DEBUG_HEADER = ''' +#define GLAD_DEBUG +typedef void (* GLADcallback)(const char *name, void *funcptr, int len_args, ...); + +GLAPI void glad_set_pre_callback(GLADcallback cb); +GLAPI void glad_set_post_callback(GLADcallback cb); +''' + +DEBUG_CODE = ''' +static GLADcallback _pre_call_callback = _pre_call_callback_default; +void glad_set_pre_callback(GLADcallback cb) { + _pre_call_callback = cb; +} + +static GLADcallback _post_call_callback = _post_call_callback_default; +void glad_set_post_callback(GLADcallback cb) { + _post_call_callback = cb; +} +''' + +DEFAULT_CALLBACK = ''' +void _pre_call_callback_default(const char *name, void *funcptr, int len_args, ...) {} +void _post_call_callback_default(const char *name, void *funcptr, int len_args, ...) {} +''' + +DEFAULT_CALLBACK_GL = ''' +void _pre_call_callback_default(const char *name, void *funcptr, int len_args, ...) {} +void _post_call_callback_default(const char *name, void *funcptr, int len_args, ...) { + GLenum error_code; + error_code = glad_glGetError(); + + if (error_code != GL_NO_ERROR) { + fprintf(stderr, "ERROR %d in %s\\n", error_code, name); + } +} +''' + + +class CDebugGenerator(CGenerator): + NAME = 'c-debug' + NAME_LONG = 'C/C++ Debug' + + def write_code_head(self, f): + CGenerator.write_code_head(self, f) + + if self.spec.NAME == 'gl': + f.write(DEFAULT_CALLBACK_GL) + else: + f.write(DEFAULT_CALLBACK) + + f.write(DEBUG_CODE) + + def write_api_header(self, f): + CGenerator.write_api_header(self, f) + f.write(DEBUG_HEADER) + + def write_function_prototype(self, fobj, func): + fobj.write('typedef {} (APIENTRYP PFN{}PROC)({});\n'.format( + func.proto.ret.to_c(), func.proto.name.upper(), + ', '.join(param.type.raw for param in func.params) + )) + fobj.write('GLAPI PFN{}PROC glad_{};\n'.format( + func.proto.name.upper(), func.proto.name + )) + fobj.write('GLAPI PFN{}PROC glad_debug_{};\n'.format( + func.proto.name.upper(), func.proto.name + )) + fobj.write('#define {0} glad_debug_{0}\n'.format(func.proto.name)) + + def write_function(self, fobj, func): + fobj.write('PFN{}PROC glad_{};\n'.format( + func.proto.name.upper(), func.proto.name + )) + + # write the default debug function + args_def = ', '.join( + '{type} arg{i}'.format(type=param.type.to_c(), i=i) + for i, param in enumerate(func.params) + ) + fobj.write('{} APIENTRY glad_debug_impl_{}({}) {{'.format( + func.proto.ret.to_c(), func.proto.name, args_def + )) + args = ', '.join('arg{}'.format(i) for i, _ in enumerate(func.params)) + args_callback = ', '.join(filter( + None, ['(void*){}'.format(func.proto.name), str(len(func.params)), args] + )) + return_def = '' + return_assign = '' + return_return = '' + # lower because of win API having VOID + if not func.proto.ret.to_c().lower() == 'void': + return_def = '\n {} ret;'.format(func.proto.ret.to_c()) + return_assign = 'ret = ' + return_return = 'return ret;' + fobj.write('\n'.join(filter(None, DEFAULT_DEBUG_IMPL.format( + name=func.proto.name, args=args, args_callback=args_callback, + return_def=return_def, return_assign=return_assign, + return_return=return_return + ).splitlines()))) + fobj.write('\n}\n') + + fobj.write('PFN{0}PROC glad_debug_{1} = glad_debug_impl_{1};\n'.format( + func.proto.name.upper(), func.proto.name + )) diff --git a/libs/glad/glad/lang/c/generator.py b/libs/glad/glad/lang/c/generator.py @@ -0,0 +1,291 @@ +import os +import sys + +from glad.lang.common.generator import Generator +from glad.lang.common.util import makefiledir + + +KHRPLATFORM = 'https://www.khronos.org/registry/egl/api/KHR/khrplatform.h' + + +class CGenerator(Generator): + NAME = 'c' + NAME_LONG = 'C/C++' + + def open(self): + suffix = '' + if not self.spec.NAME == 'gl': + suffix = '_{}'.format(self.spec.NAME) + + if self.local_files: + self.h_include = '"glad{}.h"'.format(suffix) + self._f_c = open(make_path(self.path, + 'glad{}.c'.format(suffix)), 'w') + self._f_h = open(make_path(self.path, + 'glad{}.h'.format(suffix)), 'w') + khr = self.path + else: + self.h_include = '<glad/glad{}.h>'.format(suffix) + self._f_c = open(make_path(self.path, 'src', + 'glad{}.c'.format(suffix)), 'w') + self._f_h = open(make_path(self.path, 'include', 'glad', + 'glad{}.h'.format(suffix)), 'w') + khr = os.path.join(self.path, 'include', 'KHR') + + if not self.omit_khrplatform: + khr_url = KHRPLATFORM + if os.path.exists('khrplatform.h'): + khr_url = 'file://' + os.path.abspath('khrplatform.h') + + khrplatform = os.path.join(khr, 'khrplatform.h') + if not os.path.exists(khrplatform): + if not os.path.exists(khr): + os.makedirs(khr) + self.opener.urlretrieve(khr_url, khrplatform) + + return self + + def close(self): + self._f_c.close() + self._f_h.close() + + def generate_header(self): + self._f_h.write('/*\n') + self._f_h.write(self.header) + self._f_h.write('*/\n\n') + + self._f_c.write('/*\n') + self._f_c.write(self.header) + self._f_c.write('*/\n\n') + + def generate_loader(self, features, extensions): + f = self._f_c + + if self.spec.NAME in ('egl', 'wgl'): + features = {'egl': [], 'wgl': []} + + written = set() + for api, version in self.api.items(): + for feature in features[api]: + f.write('static void load_{}(GLADloadproc load) {{\n' + .format(feature.name)) + if self.spec.NAME in ('gl', 'glx', 'wgl'): + f.write('\tif(!GLAD_{}) return;\n'.format(feature.name)) + for func in feature.functions: + f.write('\tglad_{0} = (PFN{1}PROC)load("{0}");\n' + .format(func.proto.name, func.proto.name.upper())) + f.write('}\n') + + for ext in extensions[api]: + if len(list(ext.functions)) == 0 or ext.name in written: + continue + + f.write('static void load_{}(GLADloadproc load) {{\n' + .format(ext.name)) + if self.spec.NAME in ('gl', 'glx', 'wgl'): + f.write('\tif(!GLAD_{}) return;\n'.format(ext.name)) + if ext.name == 'GLX_SGIX_video_source': f.write('#ifdef _VL_H_\n') + if ext.name == 'GLX_SGIX_dmbuffer': f.write('#ifdef _DM_BUFFER_H_\n') + for func in ext.functions: + # even if they were in written we need to load it + f.write('\tglad_{0} = (PFN{1}PROC)load("{0}");\n' + .format(func.proto.name, func.proto.name.upper())) + if ext.name in ('GLX_SGIX_video_source', 'GLX_SGIX_dmbuffer'): + f.write('#else\n') + f.write('\t(void)load;\n') + f.write('#endif\n') + f.write('}\n') + + written.add(ext.name) + + f.write('static int find_extensions{}(void) {{\n'.format(api.upper())) + if self.spec.NAME in ('gl', 'glx', 'wgl'): + f.write('\tif (!get_exts()) return 0;\n') + for ext in extensions[api]: + f.write('\tGLAD_{0} = has_ext("{0}");\n'.format(ext.name)) + f.write('\tfree_exts();\n') + f.write('\treturn 1;\n') + f.write('}\n\n') + + if api == 'glx': + f.write('static void find_core{}(Display *dpy, int screen) {{\n'.format(api.upper())) + elif api == 'wgl': + f.write('static void find_core{}(HDC hdc) {{\n'.format(api.upper())) + else: + f.write('static void find_core{}(void) {{\n'.format(api.upper())) + + self.loader.write_find_core(f) + if self.spec.NAME in ('gl', 'glx', 'wgl'): + for feature in features[api]: + f.write('\tGLAD_{} = (major == {num[0]} && minor >= {num[1]}) ||' + ' major > {num[0]};\n'.format(feature.name, num=feature.number)) + if self.spec.NAME == 'gl': + f.write('\tif (GLVersion.major > {0} || (GLVersion.major >= {0} && GLVersion.minor >= {1})) {{\n'.format(version[0], version[1])) + f.write('\t\tmax_loaded_major = {0};\n'.format(version[0])) + f.write('\t\tmax_loaded_minor = {0};\n'.format(version[1])) + f.write('\t}\n') + f.write('}\n\n') + + if api == 'glx': + f.write('int gladLoad{}Loader(GLADloadproc load, Display *dpy, int screen) {{\n'.format(api.upper())) + elif api == 'wgl': + f.write('int gladLoad{}Loader(GLADloadproc load, HDC hdc) {{\n'.format(api.upper())) + else: + f.write('int gladLoad{}Loader(GLADloadproc load) {{\n'.format(api.upper())) + + self.loader.write_begin_load(f) + + if api == 'glx': + f.write('\tfind_core{}(dpy, screen);\n'.format(api.upper())) + elif api == 'wgl': + f.write('\tfind_core{}(hdc);\n'.format(api.upper())) + else: + f.write('\tfind_core{}();\n'.format(api.upper())) + + for feature in features[api]: + f.write('\tload_{}(load);\n'.format(feature.name)) + f.write('\n\tif (!find_extensions{}()) return 0;\n'.format(api.upper())) + for ext in extensions[api]: + if len(list(ext.functions)) == 0: + continue + f.write('\tload_{}(load);\n'.format(ext.name)) + + self.loader.write_end_load(f) + f.write('}\n\n') + + self.loader.write_header_end(self._f_h) + + def generate_types(self, types): + f = self._f_h + + self.loader.write_header(f) + self.write_api_header(f) + + for type in types: + output_string = (type.raw + '\n').lstrip().replace(' ', ' ') + if output_string == '#include <KHR/khrplatform.h>\n': + if self.omit_khrplatform: + continue + elif self.local_files: + output_string = '#include "khrplatform.h"\n' + if not self.spec.NAME in ('egl',) and 'khronos' in type.raw: + continue + f.write(output_string) + + def generate_features(self, features): + f = self._f_h + write = set() + if self.spec.NAME in ('wgl',): + # These are already defined in windows.h + pass + elif self.spec.NAME in ('egl',): + self.write_enums(f, set(), features) + + for feature in features: + for func in feature.functions: + self.write_function_def(f, func) + else: + self.write_functions(f, write, set(), features) + + f = self._f_c + self.write_code_head(f) + self.loader.write(f) + self.loader.write_has_ext(f) + + if self.spec.NAME in ('gl', 'glx', 'wgl'): + for feature in features: + f.write('int GLAD_{};\n'.format(feature.name)) + + for func in write: + self.write_function(f, func) + + def generate_extensions(self, extensions, enums, functions): + write = set() + written = set(enum.name for enum in enums) | \ + set(function.proto.name for function in functions) + + f = self._f_h + self.write_functions(f, write, written, extensions) + + f = self._f_c + if self.spec.NAME in ('gl', 'glx', 'wgl'): + for ext in set(ext.name for ext in extensions): + f.write('int GLAD_{};\n'.format(ext)) + + written = set() + for ext in extensions: + if ext.name == 'GLX_SGIX_video_source': f.write('#ifdef _VL_H_\n') + if ext.name == 'GLX_SGIX_dmbuffer': f.write('#ifdef _DM_BUFFER_H_\n') + for func in ext.functions: + if func in write and func not in written: + self.write_function(f, func) + written.add(func) + if ext.name in ('GLX_SGIX_video_source', 'GLX_SGIX_dmbuffer'): f.write('#endif\n') + + def write_functions(self, f, write, written, extensions): + self.write_enums(f, written, extensions) + + for ext in extensions: + f.write('#ifndef {0}\n#define {0} 1\n'.format(ext.name)) + if self.spec.NAME in ('gl', 'glx', 'wgl'): + f.write('GLAPI int GLAD_{};\n'.format(ext.name)) + if ext.name == 'GLX_SGIX_video_source': f.write('#ifdef _VL_H_\n') + if ext.name == 'GLX_SGIX_dmbuffer': f.write('#ifdef _DM_BUFFER_H_\n') + for func in ext.functions: + if not func.proto.name in written: + self.write_function_prototype(f, func) + write.add(func) + written.add(func.proto.name) + if ext.name in ('GLX_SGIX_video_source', 'GLX_SGIX_dmbuffer'): f.write('#endif\n') + f.write('#endif\n') + + def write_enums(self, f, written, extensions): + for ext in extensions: + for enum in ext.enums: + if not enum.name in written: + f.write('#define {} {}\n'.format(enum.name, enum.value)) + written.add(enum.name) + + def write_api_header(self, f): + for api in self.api: + if api == 'glx': + f.write('GLAPI int gladLoad{}Loader(GLADloadproc, Display *dpy, int screen);\n\n'.format(api.upper())) + elif api == 'wgl': + f.write('GLAPI int gladLoad{}Loader(GLADloadproc, HDC hdc);\n\n'.format(api.upper())) + else: + f.write('GLAPI int gladLoad{}Loader(GLADloadproc);\n\n'.format(api.upper())) + + def write_code_head(self, f): + f.write('#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include {}\n'.format(self.h_include)) + + def write_extern(self, fobj): + fobj.write('#ifdef __cplusplus\nextern "C" {\n#endif\n') + + def write_extern_end(self, fobj): + fobj.write('#ifdef __cplusplus\n}\n#endif\n') + + def write_function_def(self, fobj, func): + # write a function definition instead of a prototype. + # e.g. egl uses that, since the main functions get linked in and not loaded through a function. + fobj.write('{}('.format(func.proto.ret.raw)) + fobj.write(', '.join(param.type.raw for param in func.params)) + fobj.write(');\n') + + def write_function_prototype(self, fobj, func): + fobj.write('typedef {} (APIENTRYP PFN{}PROC)({});\n'.format( + func.proto.ret.to_c(), func.proto.name.upper(), + ', '.join(param.type.raw for param in func.params)) + ) + fobj.write('GLAPI PFN{}PROC glad_{};\n'.format(func.proto.name.upper(), + func.proto.name)) + fobj.write('#define {0} glad_{0}\n'.format(func.proto.name)) + + def write_function(self, fobj, func): + fobj.write('PFN{}PROC glad_{};\n'.format(func.proto.name.upper(), + func.proto.name)) + + +def make_path(path, *args): + path = os.path.join(path, *args) + makefiledir(path) + return path diff --git a/libs/glad/glad/lang/c/loader/__init__.py b/libs/glad/glad/lang/c/loader/__init__.py @@ -0,0 +1,132 @@ + +LOAD_OPENGL_DLL = ''' +%(pre)s void* %(proc)s(const char *namez); + +#ifdef _WIN32 +#include <windows.h> +static HMODULE libGL; + +typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); +PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; + +%(pre)s +int %(init)s(void) { + libGL = LoadLibraryW(L"opengl32.dll"); + if(libGL != NULL) { + gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE)GetProcAddress( + libGL, "wglGetProcAddress"); + return gladGetProcAddressPtr != NULL; + } + + return 0; +} + +%(pre)s +void %(terminate)s(void) { + if(libGL != NULL) { + FreeLibrary(libGL); + libGL = NULL; + } +} +#else +#include <dlfcn.h> +static void* libGL; + +#ifndef __APPLE__ +typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); +PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; +#endif + +%(pre)s +int %(init)s(void) { +#ifdef __APPLE__ + static const char *NAMES[] = { + "../Frameworks/OpenGL.framework/OpenGL", + "/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" + }; +#else + static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; +#endif + + unsigned int index = 0; + for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) { + libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); + + if(libGL != NULL) { +#ifdef __APPLE__ + return 1; +#else + gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, + "glXGetProcAddressARB"); + return gladGetProcAddressPtr != NULL; +#endif + } + } + + return 0; +} + +%(pre)s +void %(terminate)s() { + if(libGL != NULL) { + dlclose(libGL); + libGL = NULL; + } +} +#endif + +%(pre)s +void* %(proc)s(const char *namez) { + void* result = NULL; + if(libGL == NULL) return NULL; + +#ifndef __APPLE__ + if(gladGetProcAddressPtr != NULL) { + result = gladGetProcAddressPtr(namez); + } +#endif + if(result == NULL) { +#ifdef _WIN32 + result = (void*)GetProcAddress(libGL, namez); +#else + result = dlsym(libGL, namez); +#endif + } + + return result; +} +''' + +LOAD_OPENGL_DLL_H = ''' +''' + +LOAD_OPENGL_GLAPI_H = ''' +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif +''' + diff --git a/libs/glad/glad/lang/c/loader/egl.py b/libs/glad/glad/lang/c/loader/egl.py @@ -0,0 +1,84 @@ +from glad.lang.common.loader import BaseLoader + + +_EGL_LOADER = ''' +int gladLoadEGL(void) { + return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress); +} +''' + +_EGL_HEADER = ''' +#ifndef __glad_egl_h_ + +#ifdef __egl_h_ +#error EGL header already included, remove this include, glad already provides it +#endif + +#define __glad_egl_h_ +#define __egl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include <windows.h> +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (* GLADloadproc)(const char *name); +''' + +_EGL_HEADER_LOADER = ''' +GLAPI int gladLoadEGL(void); +''' + +_EGL_HEADER_END = ''' +#ifdef __cplusplus +} +#endif + +#endif +''' + +_EGL_HAS_EXT = ''' +''' + + +class EGLCLoader(BaseLoader): + def write(self, fobj): + if not self.disabled: + fobj.write(_EGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn 1;\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_EGL_HAS_EXT) + + def write_header(self, fobj): + fobj.write(_EGL_HEADER) + if not self.disabled: + fobj.write(_EGL_HEADER_LOADER) + + def write_header_end(self, fobj): + fobj.write(_EGL_HEADER_END) + diff --git a/libs/glad/glad/lang/c/loader/gl.py b/libs/glad/glad/lang/c/loader/gl.py @@ -0,0 +1,242 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.c.loader import LOAD_OPENGL_DLL, LOAD_OPENGL_DLL_H, LOAD_OPENGL_GLAPI_H + + +_OPENGL_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'static', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +int gladLoadGL(void) { + int status = 0; + + if(open_gl()) { + status = gladLoadGLLoader(&get_proc); + close_gl(); + } + + return status; +} +''' + +_OPENGL_HAS_EXT = ''' +struct gladGLversionStruct GLVersion; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static const char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < num_exts_i; index++) { + exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, index); + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + free((char **)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +''' + + +_OPENGL_HEADER_START = ''' +#ifndef __glad_h_ +#define __glad_h_ +''' + +_OPENGL_HEADER_INCLUDE_ERROR = ''' +#ifdef __{0}_h_ +#error {1} header already included, remove this include, glad already provides it +#endif +#define __{0}_h_ +''' + +_OPENGL_HEADER = ''' +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include <windows.h> +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); +''' + LOAD_OPENGL_GLAPI_H + ''' +GLAPI struct gladGLversionStruct GLVersion; +''' + +_OPENGL_HEADER_LOADER = ''' +GLAPI int gladLoadGL(void); +''' + LOAD_OPENGL_DLL_H + +_OPENGL_HEADER_END = ''' +#ifdef __cplusplus +} +#endif + +#endif +''' + +_FIND_VERSION = ''' + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; +''' + + +class OpenGLCLoader(BaseLoader): + def write(self, fobj): + if not self.disabled and 'gl' in self.apis: + fobj.write(_OPENGL_LOADER) + + def write_begin_load(self, fobj): + fobj.write('\tGLVersion.major = 0; GLVersion.minor = 0;\n') + fobj.write('\tglGetString = (PFNGLGETSTRINGPROC)load("glGetString");\n') + fobj.write('\tif(glGetString == NULL) return 0;\n') + fobj.write('\tif(glGetString(GL_VERSION) == NULL) return 0;\n') + + def write_end_load(self, fobj): + fobj.write('\treturn GLVersion.major != 0 || GLVersion.minor != 0;\n') + + def write_find_core(self, fobj): + fobj.write(_FIND_VERSION) + + def write_find_core_end(self, fobj): + fobj.write(_FIND_VERSION) + + def write_has_ext(self, fobj): + fobj.write(_OPENGL_HAS_EXT) + + def write_header(self, fobj): + fobj.write(_OPENGL_HEADER_START) + written = set() + for api, hname, name in [ + ('gl', 'gl', 'OpenGL'), ('gles1', 'gl', 'OpenGL ES 1'), + ('gles2', 'gl2', 'OpenGL ES 2'), ('gles2', 'gl3', 'OpenGL ES 3') + ]: + if api in self.apis and hname not in written: + fobj.write(_OPENGL_HEADER_INCLUDE_ERROR.format(hname, name)) + written.add(hname) + + fobj.write(_OPENGL_HEADER) + if not self.disabled and 'gl' in self.apis: + fobj.write(_OPENGL_HEADER_LOADER) + + def write_header_end(self, fobj): + fobj.write(_OPENGL_HEADER_END) diff --git a/libs/glad/glad/lang/c/loader/glx.py b/libs/glad/glad/lang/c/loader/glx.py @@ -0,0 +1,148 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.c.loader import LOAD_OPENGL_DLL, LOAD_OPENGL_DLL_H, LOAD_OPENGL_GLAPI_H + +_GLX_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'static', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +int gladLoadGLX(Display *dpy, int screen) { + int status = 0; + + if(open_gl()) { + status = gladLoadGLXLoader((GLADloadproc)get_proc, dpy, screen); + close_gl(); + } + + return status; +} +''' + +_GLX_HEADER_START = ''' +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +''' + +#include <glad/glad.h> + +_WGL_HEADER_MID = ''' +#ifndef __glad_glxext_h_ + +#ifdef __glxext_h_ +#error GLX header already included, remove this include, glad already provides it +#endif + +#define __glad_glxext_h_ +#define __glxext_h_ + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (* GLADloadproc)(const char *name); +''' + LOAD_OPENGL_GLAPI_H + +_GLX_HEADER_LOADER = ''' +GLAPI int gladLoadGLX(Display *dpy, int screen); +''' + LOAD_OPENGL_DLL_H + +_GLX_HEADER_END = ''' +#ifdef __cplusplus +} +#endif + +#endif +''' + +_GLX_HAS_EXT = ''' +static Display *GLADGLXDisplay = 0; +static int GLADGLXscreen = 0; + +static int get_exts(void) { + return 1; +} + +static void free_exts(void) { + return; +} + +static int has_ext(const char *ext) { + const char *terminator; + const char *loc; + const char *extensions; + + if(!GLAD_GLX_VERSION_1_1) + return 0; + + extensions = glXQueryExtensionsString(GLADGLXDisplay, GLADGLXscreen); + + if(extensions == NULL || ext == NULL) + return 0; + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) + break; + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\\0')) + { + return 1; + } + extensions = terminator; + } + + return 0; +} + +''' + + +class GLXCLoader(BaseLoader): + def write(self, fobj): + if not self.disabled: + fobj.write(_GLX_LOADER) + + def write_begin_load(self, fobj): + fobj.write('\tglXQueryVersion = (PFNGLXQUERYVERSIONPROC)load("glXQueryVersion");\n') + fobj.write('\tif(glXQueryVersion == NULL) return 0;\n') + + def write_end_load(self, fobj): + fobj.write('\treturn 1;\n') + + def write_find_core(self, fobj): + fobj.write('\tint major = 0, minor = 0;\n') + fobj.write('\tif(dpy == 0 && GLADGLXDisplay == 0) {\n') + fobj.write('\t\tdpy = XOpenDisplay(0);\n') + fobj.write('\t\tscreen = XScreenNumberOfScreen(XDefaultScreenOfDisplay(dpy));\n') + fobj.write('\t} else if(dpy == 0) {\n') + fobj.write('\t\tdpy = GLADGLXDisplay;\n') + fobj.write('\t\tscreen = GLADGLXscreen;\n') + fobj.write('\t}\n') + fobj.write('\tglXQueryVersion(dpy, &major, &minor);\n') + fobj.write('\tGLADGLXDisplay = dpy;\n') + fobj.write('\tGLADGLXscreen = screen;\n') + + def write_has_ext(self, fobj): + fobj.write(_GLX_HAS_EXT) + + def write_header(self, fobj): + fobj.write(_GLX_HEADER_START) + if self.local_files: + fobj.write('#include "glad.h"\n') + else: + fobj.write('#include <glad/glad.h>\n') + fobj.write(_WGL_HEADER_MID) + if not self.disabled: + fobj.write(_GLX_HEADER_LOADER) + + def write_header_end(self, fobj): + fobj.write(_GLX_HEADER_END) + diff --git a/libs/glad/glad/lang/c/loader/wgl.py b/libs/glad/glad/lang/c/loader/wgl.py @@ -0,0 +1,142 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.c.loader import LOAD_OPENGL_DLL, LOAD_OPENGL_DLL_H, LOAD_OPENGL_GLAPI_H + +_WGL_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'static', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +int gladLoadWGL(HDC hdc) { + int status = 0; + + if(open_gl()) { + status = gladLoadWGLLoader((GLADloadproc)get_proc, hdc); + close_gl(); + } + + return status; +} +''' + +_WGL_HEADER_START = ''' +#ifndef WINAPI +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# include <windows.h> +#endif + +''' + +#include <glad/glad.h> + +_WGL_HEADER_MID = ''' +#ifndef __glad_wglext_h_ + +#ifdef __wglext_h_ +#error WGL header already included, remove this include, glad already provides it +#endif + +#define __glad_wglext_h_ +#define __wglext_h_ + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (* GLADloadproc)(const char *name); +''' + LOAD_OPENGL_GLAPI_H + +_WGL_HEADER_LOADER = ''' +GLAPI int gladLoadWGL(HDC hdc); +''' + LOAD_OPENGL_DLL_H + +_WGL_HEADER_END = ''' +#ifdef __cplusplus +} +#endif + +#endif +''' + +_WGL_HAS_EXT = ''' +static HDC GLADWGLhdc = (HDC)INVALID_HANDLE_VALUE; + +static int get_exts(void) { + return 1; +} + +static void free_exts(void) { + return; +} + +static int has_ext(const char *ext) { + const char *terminator; + const char *loc; + const char *extensions; + + if(wglGetExtensionsStringEXT == NULL && wglGetExtensionsStringARB == NULL) + return 0; + + if(wglGetExtensionsStringARB == NULL || GLADWGLhdc == INVALID_HANDLE_VALUE) + extensions = wglGetExtensionsStringEXT(); + else + extensions = wglGetExtensionsStringARB(GLADWGLhdc); + + if(extensions == NULL || ext == NULL) + return 0; + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) + break; + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\\0')) + { + return 1; + } + extensions = terminator; + } + + return 0; +} +''' + +class WGLCLoader(BaseLoader): + def write(self, fobj): + if not self.disabled: + fobj.write(_WGL_LOADER) + + def write_begin_load(self, fobj): + fobj.write('\twglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)load("wglGetExtensionsStringARB");\n') + fobj.write('\twglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)load("wglGetExtensionsStringEXT");\n') + fobj.write('\tif(wglGetExtensionsStringARB == NULL && wglGetExtensionsStringEXT == NULL) return 0;\n') + + def write_end_load(self, fobj): + fobj.write('\treturn 1;\n') + + def write_find_core(self, fobj): + fobj.write('\tGLADWGLhdc = hdc;\n') + + def write_has_ext(self, fobj): + fobj.write(_WGL_HAS_EXT) + + def write_header(self, fobj): + fobj.write(_WGL_HEADER_START) + if self.local_files: + fobj.write('#include "glad.h"\n') + else: + fobj.write('#include <glad/glad.h>\n') + fobj.write(_WGL_HEADER_MID) + if not self.disabled: + fobj.write(_WGL_HEADER_LOADER) + + def write_header_end(self, fobj): + fobj.write(_WGL_HEADER_END) diff --git a/libs/glad/glad/lang/common/__init__.py b/libs/glad/glad/lang/common/__init__.py diff --git a/libs/glad/glad/lang/common/generator.py b/libs/glad/glad/lang/common/generator.py @@ -0,0 +1,242 @@ +from collections import defaultdict +from datetime import datetime +from itertools import chain +import os.path +import sys + +from glad.lang.common.loader import NullLoader +from glad.opener import URLOpener +from glad.util import api_name +import glad + + +if sys.version_info >= (3, 0): + from urllib.parse import urlencode +else: + from urllib import urlencode + + +HEADER_TEMPLATE = ''' + {apis_named} loader generated by glad {version} on {date}. + + Language/Generator: {language} + Specification: {specification} + APIs: {apis} + Profile: {profile} + Extensions: + {extensions} + Loader: {loader} + Local files: {local_files} + Omit khrplatform: {omit_khrplatform} + + Commandline: + {commandline} + Online: + {online} +''' + + +class Generator(object): + NAME = None + NAME_LONG = None + URL = 'http://glad.dav1d.de' + + def __init__(self, path, spec, api, extension_names=None, loader=None, + opener=None, local_files=False, omit_khrplatform=False, + header_template=HEADER_TEMPLATE): + self.path = os.path.abspath(path) + + self.spec = spec + for a in api: + if a not in self.spec.features: + raise ValueError( + 'Unknown API "{0}" for specification "{1}"' + .format(a, self.spec.NAME) + ) + self.api = api + self.extension_names = extension_names + + self.has_loader = not loader.disabled + self.loader = loader + if self.loader is None: + self.loader = NullLoader + + self.opener = opener + if self.opener is None: + self.opener = URLOpener.default() + + self.local_files = local_files + self.omit_khrplatform = omit_khrplatform + + self._header_template = header_template + + def open(self): + raise NotImplementedError + + def close(self): + raise NotImplementedError + + def __enter__(self): + self.open() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + def generate(self): + features = list() + for api, version in self.api.items(): + features.extend(self.spec.features[api]) + + if version is None: + version = list(self.spec.features[api].keys())[-1] + self.api[api] = version + + if version not in self.spec.features[api]: + raise ValueError( + 'Unknown version "{0}" for specification "{1}"' + .format(version, self.spec.NAME) + ) + + if self.extension_names is None: + self.extension_names = list(chain.from_iterable(self.spec.extensions[a] + for a in self.api)) + + # sort and eliminate duplicates + self.extension_names = list(sorted(set(self.extension_names))) + + e = list(chain.from_iterable(self.spec.extensions[a] for a in self.api)) + for ext in self.extension_names: + if ext not in e: + raise ValueError( + 'Invalid extension "{0}" for specification "{1}"' + .format(ext, self.spec.NAME) + ) + + self.generate_header() + + types = [t for t in self.spec.types if t.api is None or t.api in self.api] + self.generate_types(types) + + f = list() + for api, version in self.api.items(): + f.extend([value for key, value in self.spec.features[api].items() + if key <= version]) + enums, functions = merge(f) + self.generate_features(f) + + extensions = list() + for api in self.api: + extensions.extend(self.spec.extensions[api][ext] + for ext in self.extension_names if ext + in self.spec.extensions[api]) + self.generate_extensions(extensions, enums, functions) + + fs = defaultdict(list) + es = defaultdict(list) + for api, version in self.api.items(): + fs[api].extend( + [value for key, value in + self.spec.features[api].items() if key <= version] + ) + es[api].extend(self.spec.extensions[api][ext] + for ext in self.extension_names if ext + in self.spec.extensions[api]) + self.generate_loader(fs, es) + + @property + def header(self): + apis_named = ', '.join(sorted(set(api_name(api) for api in self.api))) + date = datetime.now().strftime('%c') + language = self.NAME_LONG + specification = self.spec.NAME + apis = ', '.join('{}={}'.format(api, '.'.join(map(str, version))) for api, version in self.api.items()) + profile = getattr(self.spec, 'profile', '-') + extensions = ',\n '.join(self.extension_names) + online = self.online + if len(online) > 2000: + online = 'Too many extensions' + + return self._header_template.format( + apis_named=apis_named, + version=glad.__version__, + date=date, + language=language, + specification=specification, + apis=apis, + profile=profile, + extensions=extensions, + loader=self.has_loader, + local_files=self.local_files, + omit_khrplatform=self.omit_khrplatform, + commandline=self.commandline, + online=online + ) + + @property + def commandline(self): + profile = getattr(self.spec, 'profile', None) + if profile is not None: + profile = '--profile="{}"'.format(profile) + + api = '--api="{}"'.format(','.join( + '{}={}'.format(api, '.'.join(map(str, version))) for api, version in self.api.items()) + ) + generator = '--generator="{}"'.format(self.NAME) + specification = '--spec="{}"'.format(self.spec.NAME) + loader = '' if self.has_loader else '--no-loader' + extensions = '--extensions="{}"'.format(','.join(self.extension_names)) + local_files = '--local-files' if self.local_files else '' + omit_khrplatform = '--omit-khrplatform' if self.omit_khrplatform else '' + + return ' '.join(filter(None, [ + profile, api, generator, specification, + loader, local_files, omit_khrplatform, extensions + ])) + + @property + def online(self): + profile = getattr(self.spec, 'profile', None) + if profile is not None: + profile = ('profile', profile) + + api = [('api', s) for s in ('{}={}'.format(api, '.'.join(map(str, version))) for api, version in self.api.items())] + generator = ('language', self.NAME) + specification = ('specification', self.spec.NAME) + loader = ('loader', 'on') if self.has_loader else None + extensions = [('extensions', ext) for ext in self.extension_names] + + data = [profile, generator, specification, loader] + data.extend(api) + data.extend(extensions) + data = list(filter(None, data)) + serialized = urlencode(data) + + # TODO: --local-files, --omit-khrplatform + return '{}/#{}'.format(self.URL, serialized) + + def generate_header(self): + raise NotImplementedError + + def generate_loader(self, features, extensions): + raise NotImplementedError + + def generate_types(self, types): + raise NotImplementedError + + def generate_features(self, features): + raise NotImplementedError + + def generate_extensions(self, extensions, enums, functions): + raise NotImplementedError + + +def merge(features): + enums = set() + functions = set() + + for feature in features: + enums |= set(feature.enums) + functions |= set(feature.functions) + + return enums, functions diff --git a/libs/glad/glad/lang/common/loader.py b/libs/glad/glad/lang/common/loader.py @@ -0,0 +1,60 @@ +class BaseLoader(object): + def __init__(self, apis, disabled=False, local_files=False): + self.apis = apis + self.disabled = disabled + self.local_files = local_files + + def write(self, fobj): + raise NotImplementedError + + def write_begin_load(self, fobj): + raise NotImplementedError + + def write_end_load(self, fobj): + raise NotImplementedError + + def write_find_core(self, fobj): + raise NotImplementedError + + def write_has_ext(self, fobj): + raise NotImplementedError + + def write_header(self, fobj): + raise NotImplementedError + + def write_header_end(self, fobj): + raise NotImplementedError + + +class NullLoader(BaseLoader): + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + pass + + def write_header_end(self, fobj): + pass + + def write_has_ext(self, fobj): + pass + + def write(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write_find_core(self, fobj): + pass + + def __getattr__(self, name): + try: + return self.__getattribute__(name) + except AttributeError: + pass + + def dummy(*args, **kwargs): + pass + return dummy + diff --git a/libs/glad/glad/lang/common/util.py b/libs/glad/glad/lang/common/util.py @@ -0,0 +1,13 @@ +import os.path +import os + + +def enforce(exp, message, exc): + if not exp: + raise exc(message) + + +def makefiledir(path): + dir = os.path.split(path)[0] + if not os.path.exists(dir): + os.makedirs(dir)+ \ No newline at end of file diff --git a/libs/glad/glad/lang/d/__init__.py b/libs/glad/glad/lang/d/__init__.py @@ -0,0 +1,25 @@ +from glad.lang.d.loader.egl import EGLDLoader +from glad.lang.d.loader.gl import OpenGLDLoader +from glad.lang.d.loader.glx import GLXDLoader +from glad.lang.d.loader.wgl import WGLDLoader + +from glad.lang.d.generator import DGenerator + + +_specs = { + 'egl': EGLDLoader, + 'gl': OpenGLDLoader, + 'glx': GLXDLoader, + 'wgl': WGLDLoader +} + +_generators = { + 'd': DGenerator, +} + + +def get_generator(name, spec): + gen = _generators.get(name) + loader = _specs.get(spec) + + return gen, loader diff --git a/libs/glad/glad/lang/d/generator.py b/libs/glad/glad/lang/d/generator.py @@ -0,0 +1,861 @@ +from itertools import chain +import os.path +import sys + +from glad.lang.common.generator import Generator +from glad.lang.common.util import makefiledir + + +if sys.version_info >= (3, 0): + from io import StringIO + basestring = str +else: + from StringIO import StringIO + + +def _gl_types(gen, f): + gen.write_opaque_struct(f, '__GLsync') + gen.write_alias(f, 'GLsync', '__GLsync*') + gen.write_opaque_struct(f, '_cl_context') + gen.write_opaque_struct(f, '_cl_event') + gen.write_extern(f) + gen.write_alias( + f, + 'GLDEBUGPROC', 'void function(GLenum, GLenum, ' + 'GLuint, GLenum, GLsizei, in GLchar*, GLvoid*)' + ) + gen.write_alias(f, 'GLDEBUGPROCARB', 'GLDEBUGPROC') + gen.write_alias(f, 'GLDEBUGPROCKHR', 'GLDEBUGPROC') + gen.write_alias( + f, + 'GLDEBUGPROCAMD', 'void function(GLuint, GLenum, ' + 'GLenum, GLsizei, in GLchar*, GLvoid*)' + ) + gen.write_extern_end(f) + + +def _egl_types(gen, f): + io = StringIO() + gen.write_opaque_struct(io, 'egl_native_pixmap_t') + + f.write(''' +// Thanks to @jpf91 (github) for these declarations +version(Windows) { + import core.sys.windows.windows; + alias EGLNativeDisplayType = HDC; + alias EGLNativePixmapType = HBITMAP; + alias EGLNativeWindowType = HWND; +} else version(Symbian) { + alias EGLNativeDisplayType = int; + alias EGLNativeWindowType = void*; + alias EGLNativePixmapType = void*; +} else version(Android) { + //import android.native_window; + //struct egl_native_pixmap_t; + ''' + io.getvalue() + ''' + //alias ANativeWindow* EGLNativeWindowType; + //alias egl_native_pixmap_t* EGLNativePixmapType; + alias EGLNativeWindowType = void*; + alias EGLNativePixmapType = void*; + alias EGLNativeDisplayType = void*; +} else version(linux) { + version(Xlib) { + import X11.Xlib; + import X11.Xutil; + alias EGLNativeDisplayType = Display*; + alias EGLNativePixmapType = Pixmap; + alias EGLNativeWindowType = Window; + } else { + alias EGLNativeDisplayType = void*; + alias EGLNativePixmapType = uint; + alias EGLNativeWindowType = uint; + } +} +alias EGLObjectKHR = void*; +alias EGLLabelKHR = void*; + +extern(System) { +alias EGLSetBlobFuncANDROID = void function(const(void)*, EGLsizeiANDROID, const(void)*, EGLsizeiANDROID); +alias EGLGetBlobFuncANDROID = EGLsizeiANDROID function(const(void)*, EGLsizeiANDROID, const(void)* EGLsizeiANDROID); +struct EGLClientPixmapHI { + void *pData; + EGLint iWidth; + EGLint iHeight; + EGLint iStride; +} +alias EGLDEBUGPROCKHR = void function(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); +} +''') + gen.write_extern(f) + gen.write_opaque_struct(f, '_cl_event') + gen.write_extern_end(f) + + +def _glx_types(gen, f): + f.write(''' +version(Xlib) { + import X11.Xlib; + import X11.Xutil; +} else { + alias Bool = int; + alias Status = int; + alias VisualID = uint; + alias XPointer = byte*; + alias XID = uint; + alias Colormap = XID; + alias Display = void; + alias Font = XID; + alias Window = XID; + alias Drawable = XID; + alias Pixmap = XID; + alias Cursor = XID; + alias GContext = XID; + alias KeySym = XID; + + extern(System) { + // Borrowed from derelict + struct XExtData { + int number; + XExtData* next; + extern(C) int function(XExtData*) free_private; + XPointer private_data; + } + + struct Visual { + XExtData* ext_data; + VisualID visualid; + int _class; + uint red_mask, green_mask, blue_mask; + int bits_per_rgb; + int map_entries; + } + + struct XVisualInfo { + Visual *visual; + VisualID visualid; + int screen; + int depth; + int _class; + uint red_mask; + uint green_mask; + uint blue_mask; + int colormap_size; + int bits_per_rgb; + } + } +} + +alias DMbuffer = void*; +alias DMparams = void*; +alias VLNode = void*; +alias VLPath = void*; +alias VLServer = void*; + +alias int64_t = long; +alias uint64_t = ulong; +alias int32_t = int; + +alias GLXContextID = uint; +alias GLXPixmap = uint; +alias GLXDrawable = uint; +alias GLXPbuffer = uint; +alias GLXWindow = uint; +alias GLXFBConfigID = uint; +alias GLXVideoCaptureDeviceNV = XID; +alias GLXPbufferSGIX = XID; +alias GLXVideoSourceSGIX = XID; +alias GLXVideoDeviceNV = uint; + + +extern(System) { + alias __GLXextFuncPtr = void function(); + + struct GLXPbufferClobberEvent { + int event_type; /* GLX_DAMAGED or GLX_SAVED */ + int draw_type; /* GLX_WINDOW or GLX_PBUFFER */ + ulong serial; /* # of last request processed by server */ + Bool send_event; /* true if this came for SendEvent request */ + Display *display; /* display the event was read from */ + GLXDrawable drawable; /* XID of Drawable */ + uint buffer_mask; /* mask indicating which buffers are affected */ + uint aux_buffer; /* which aux buffer was affected */ + int x, y; + int width, height; + int count; /* if nonzero, at least this many more */ + } + + struct GLXBufferSwapComplete { + int type; + ulong serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + GLXDrawable drawable; /* drawable on which event was requested in event mask */ + int event_type; + long ust; + long msc; + long sbc; + } + + union GLXEvent { + GLXPbufferClobberEvent glxpbufferclobber; + GLXBufferSwapComplete glxbufferswapcomplete; + int[24] pad; + } + + struct GLXBufferClobberEventSGIX { + int type; + ulong serial; /* # of last request processed by server */ + Bool send_event; /* true if this came for SendEvent request */ + Display *display; /* display the event was read from */ + GLXDrawable drawable; /* i.d. of Drawable */ + int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ + int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ + uint mask; /* mask indicating which buffers are affected*/ + int x, y; + int width, height; + int count; /* if nonzero, at least this many more */ + } + + struct GLXHyperpipeNetworkSGIX { + char[80] pipeName; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int networkId; + } + + struct GLXHyperpipeConfigSGIX { + char[80] pipeName; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int channel; + uint participationType; + int timeSlice; + } + + struct GLXPipeRect { + char[80] pipeName; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int srcXOrigin, srcYOrigin, srcWidth, srcHeight; + int destXOrigin, destYOrigin, destWidth, destHeight; + } + + struct GLXPipeRectLimits { + char[80] pipeName; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int XOrigin, YOrigin, maxHeight, maxWidth; + } +} +''') + gen.write_extern(f) + gen.write_opaque_struct(f, '__GLXcontextRec') + gen.write_alias(f, 'GLXContext', '__GLXcontextRec*') + gen.write_opaque_struct(f, '__GLXFBConfigRec') + gen.write_alias(f, 'GLXFBConfig', '__GLXFBConfigRec*') + gen.write_alias(f, 'GLXFBConfigSGIX', '__GLXFBConfigRec*') + gen.write_extern_end(f) + + +def _wgl_types(gen, f): + f.write(''' +version(Windows) { + public import core.sys.windows.windows; +} else { + alias BOOL = int; + alias CHAR = char; + alias WORD = ushort; + alias DWORD = uint; + alias FLOAT = float; + alias HANDLE = void*; + alias HDC = HANDLE; + alias HGLRC = HANDLE; + alias INT = int; + alias LPCSTR = const(CHAR)*; + alias LPVOID = void*; + alias UINT = uint; + alias USHORT = ushort; + alias VOID = void; + alias COLORREF = DWORD; + alias HENHMETAFILE = HANDLE; + alias BYTE = byte; +} + +alias PROC = HANDLE; + +extern(System) { + struct RECT { + int left; + int top; + int right; + int bottom; + } + + struct LAYERPLANEDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerType; + BYTE bReserved; + COLORREF crTransparent; + } + + struct PIXELFORMATDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerType; + BYTE bReserved; + DWORD dwLayerMask; + DWORD dwVisibleMask; + DWORD dwDamageMask; + } + + struct POINTFLOAT { + FLOAT x; + FLOAT y; + } + + struct GLYPHMETRICSFLOAT { + FLOAT gmfBlackBoxX; + FLOAT gmfBlackBoxY; + POINTFLOAT gmfptGlyphOrigin; + FLOAT gmfCellIncX; + FLOAT gmfCellIncY; + } + alias PGLYPHMETRICSFLOAT = GLYPHMETRICSFLOAT*; + alias LPGLYPHMETRICSFLOAT = GLYPHMETRICSFLOAT; + + struct GPU_DEVICE { + DWORD cb; + CHAR[32] DeviceName; + CHAR[128] DeviceString; + DWORD Flags; + RECT rcVirtualScreen; + } + + alias PGPU_DEVICE = GPU_DEVICE; +} +''') + gen.write_opaque_struct(f, 'HPBUFFERARB') + gen.write_opaque_struct(f, 'HPBUFFEREXT') + gen.write_opaque_struct(f, 'HVIDEOOUTPUTDEVICENV') + gen.write_opaque_struct(f, 'HPVIDEODEV') + gen.write_opaque_struct(f, 'HPGPUNV') + gen.write_opaque_struct(f, 'HGPUNV') + gen.write_opaque_struct(f, 'HVIDEOINPUTDEVICENV') + + +DTYPES = { + '__pre': { + 'egl': 'import core.stdc.stdint : intptr_t;\n\n' + }, + + '__other': { + 'gl': _gl_types, + 'egl': _egl_types, + 'glx': _glx_types, + 'wgl': _wgl_types + }, + + 'gl': { + 'GLenum': 'uint', 'GLvoid': 'void', 'GLboolean': 'ubyte', + 'GLbitfield': 'uint', 'GLchar': 'char', 'GLbyte': 'byte', + 'GLshort': 'short', 'GLint': 'int', 'GLclampx': 'int', + 'GLsizei': 'int', 'GLubyte': 'ubyte', 'GLushort': 'ushort', + 'GLuint': 'uint', 'GLhalf': 'ushort', 'GLfloat': 'float', + 'GLclampf': 'float', 'GLdouble': 'double', 'GLclampd': 'double', + 'GLfixed': 'int', 'GLintptr': 'ptrdiff_t', 'GLsizeiptr': 'ptrdiff_t', + 'GLintptrARB': 'ptrdiff_t', 'GLsizeiptrARB': 'ptrdiff_t', + 'GLcharARB': 'byte', 'GLhandleARB': 'uint', 'GLhalfARB': 'ushort', + 'GLhalfNV': 'ushort', 'GLint64EXT': 'long', 'GLuint64EXT': 'ulong', + 'GLint64': 'long', 'GLuint64': 'ulong', + 'GLvdpauSurfaceNV': 'ptrdiff_t', 'GLeglImageOES': 'void*' + }, + 'egl': { + 'EGLBoolean': 'uint', 'EGLenum': 'uint', 'EGLAttribKHR': 'intptr_t', + 'EGLAttrib': 'intptr_t', 'EGLClientBuffer': 'void*', 'EGLConfig': 'void*', + 'EGLContext': 'void*', 'EGLDeviceEXT': 'void*', 'EGLDisplay': 'void*', + 'EGLImage': 'void*', 'EGLImageKHR': 'void*', 'EGLOutputLayerEXT': 'void*', + 'EGLOutputPortEXT': 'void*', 'EGLStreamKHR': 'void*', 'EGLSurface': 'void*', + 'EGLSync': 'void*', 'EGLSyncKHR': 'void*', 'EGLSyncNV': 'void*', + '__eglMustCastToProperFunctionPointerType': 'void function()', + 'EGLint': 'int', 'EGLTimeKHR': 'ulong', 'EGLTime': 'ulong', + 'EGLTimeNV': 'ulong', 'EGLuint64NV': 'ulong', + 'EGLuint64KHR': 'ulong', 'EGLuint64MESA': 'ulong', + 'EGLsizeiANDROID': 'ptrdiff_t', 'EGLNativeFileDescriptorKHR': 'int' + }, + 'glx': { + 'GLboolean': 'ubyte', 'GLenum': 'uint', 'GLint': 'int', + 'GLsizei': 'int', 'GLubyte': 'ubyte', 'GLuint': 'uint', + 'GLfloat': 'float', 'GLbitfield': 'uint', 'GLintptr': 'ptrdiff_t', + 'GLsizeiptr': 'ptrdiff_t' + + }, + 'wgl': { + 'GLbitfield': 'uint', 'GLenum': 'uint', 'GLfloat': 'float', + 'GLint': 'int', 'GLsizei': 'int', 'GLuint': 'uint', + 'GLushort': 'ushort', 'INT32': 'int', 'INT64': 'long', + 'GLboolean': 'ubyte' + }, + + 'SpecialNumbers': { + 'gl': [ + ('GL_FALSE', '0', 'ubyte'), ('GL_TRUE', '1', 'ubyte'), + ('GL_NO_ERROR', '0', 'uint'), ('GL_NONE', '0', 'uint'), + ('GL_ZERO', '0', 'uint'), ('GL_ONE', '1', 'uint'), + ('GL_NONE_OES', '0', 'uint'), + ('GL_INVALID_INDEX', '0xFFFFFFFF', 'uint'), + ('GL_TIMEOUT_IGNORED', '0xFFFFFFFFFFFFFFFF', 'ulong'), + ('GL_TIMEOUT_IGNORED_APPLE', '0xFFFFFFFFFFFFFFFF', 'ulong'), + ('GL_VERSION_ES_CL_1_0', '1', 'uint'), ('GL_VERSION_ES_CM_1_1', '1', 'uint'), + ('GL_VERSION_ES_CL_1_1', '1', 'uint') + ], + 'egl': [ + ('EGL_DONT_CARE', '-1', 'int'), ('EGL_UNKNOWN', '-1', 'int'), + ('EGL_NO_NATIVE_FENCE_FD_ANDROID', '-1', 'uint'), + ('EGL_DEPTH_ENCODING_NONE_NV', '0', 'uint'), + ('EGL_NO_CONTEXT', 'cast(EGLContext)0', 'EGLContext'), + ('EGL_NO_DEVICE_EXT', 'cast(EGLDeviceEXT)0', 'EGLDeviceEXT'), + ('EGL_NO_DISPLAY', 'cast(EGLDisplay)0', 'EGLDisplay'), + ('EGL_NO_IMAGE', 'cast(EGLImage)0', 'EGLImage'), + ('EGL_NO_IMAGE_KHR', 'cast(EGLImageKHR)0', 'EGLImageKHR'), + ('EGL_DEFAULT_DISPLAY', 'cast(EGLNativeDisplayType)0', 'EGLNativeDisplayType'), + ('EGL_NO_FILE_DESCRIPTOR_KHR', 'cast(EGLNativeFileDescriptorKHR)-1', 'EGLNativeFileDescriptorKHR'), + ('EGL_NO_OUTPUT_LAYER_EXT', 'cast(EGLOutputLayerEXT)0', 'EGLOutputLayerEXT'), + ('EGL_NO_OUTPUT_PORT_EXT', 'cast(EGLOutputPortEXT)0', 'EGLOutputPortEXT'), + ('EGL_NO_STREAM_KHR', 'cast(EGLStreamKHR)0', 'EGLStreamKHR'), + ('EGL_NO_SURFACE', 'cast(EGLSurface)0', 'EGLSurface'), + ('EGL_NO_SYNC', 'cast(EGLSync)0', 'EGLSync'), + ('EGL_NO_SYNC_KHR', 'cast(EGLSyncKHR)0', 'EGLSyncKHR'), + ('EGL_NO_SYNC_NV', 'cast(EGLSyncNV)0', 'EGLSyncNV'), + ('EGL_DISPLAY_SCALING', '10000', 'uint'), + ('EGL_FOREVER', '0xFFFFFFFFFFFFFFFF', 'ulong'), + ('EGL_FOREVER_KHR', '0xFFFFFFFFFFFFFFFF', 'ulong'), + ('EGL_FOREVER_NV', '0xFFFFFFFFFFFFFFFF', 'ulong') + ], + 'glx': [ + ('GLX_DONT_CARE', '0xFFFFFFFF', 'uint'), + ('GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB', '0', 'uint') + ], + 'wgl': [ + ('WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB', '0', 'uint'), + ('WGL_FONT_LINES', '0', 'uint'), + ('WGL_FONT_POLYGONS', 1, 'uint') + ] + } +} + + +class BaseDGenerator(Generator): + NAME = 'd' + NAME_LONG = 'D' + + def open(self): + self._f_loader = open(self.make_path(self.LOADER), 'w') + self._f_gl = open(self.make_path(self.PACKAGE), 'w') + self._f_types = open(self.make_path(self.TYPES), 'w') + self._f_enums = open(self.make_path(self.ENUMS), 'w') + self._f_funcs = open(self.make_path(self.FUNCS), 'w') + self._f_exts = open(self.make_path(self.EXT), 'w') + + def close(self): + self._f_loader.close() + self._f_gl.close() + self._f_types.close() + self._f_enums.close() + self._f_funcs.close() + self._f_exts.close() + + @property + def PACKAGE(self): + return 'all' + + def generate_header(self): + self._f_gl.write('/*\n') + self._f_gl.write(self.header) + self._f_gl.write('*/\n\n') + + def generate_loader(self, features, extensions): + f = self._f_loader + + rfeatures = features + if self.spec.NAME in ('egl', 'wgl'): + features = {'egl': [], 'wgl': []} + + self.write_module(f, self.LOADER) + self.write_imports(f, [self.FUNCS, self.EXT, self.ENUMS, self.TYPES]) + + self.loader.write(f) + self.loader.write_has_ext(f) + + written = set() + for api, version in self.api.items(): + loadername = 'Load' if self.LOAD_GL_PREFIX else 'load' + f.write('bool {}{}{}(Loader load) {{\n' + .format(self.LOAD_GL_PREFIX, loadername, api.upper())) + self.loader.write_begin_load(f) + f.write('\tfind_core{}();\n'.format(api.upper())) + for feature in features[api]: + f.write('\tload_{}(load);\n'.format(feature.name)) + f.write('\n\tfind_extensions{}();\n'.format(api.upper())) + for ext in extensions[api]: + if len(list(ext.functions)) == 0: + continue + f.write('\tload_{}(load);\n'.format(ext.name)) + self.loader.write_end_load(f) + f.write('}\n\n') + + f.write('private {\n\n') + + f.write('void find_core{}() {{\n'.format(api.upper())) + self.loader.write_find_core(f) + if self.spec.NAME == 'gl': + for feature in features[api]: + f.write('\t{} = (major == {num[0]} && minor >= {num[1]}) ||' + ' major > {num[0]};\n'.format(feature.name, num=feature.number)) + f.write('\treturn;\n') + f.write('}\n\n') + + f.write('void find_extensions{}() {{\n'.format(api.upper())) + if self.spec.NAME == 'gl': + for ext in extensions[api]: + f.write('\t{0} = has_ext("{0}");\n'.format(ext.name)) + f.write('\treturn;\n') + f.write('}\n\n') + + for feature in features[api]: + f.write('void load_{}(Loader load) {{\n' + .format(feature.name)) + if self.spec.NAME == 'gl': + f.write('\tif(!{}) return;\n'.format(feature.name)) + for func in feature.functions: + f.write('\t{name} = cast(typeof({name}))load("{name}");\n' + .format(name=func.proto.name)) + f.write('\treturn;\n}\n\n') + + for ext in extensions[api]: + if len(list(ext.functions)) == 0 or ext.name in written: + continue + + f.write('void load_{}(Loader load) {{\n' + .format(ext.name)) + if self.spec.NAME == 'gl': + f.write('\tif(!{}) return;\n'.format(ext.name)) + for func in ext.functions: + # even if they were in written we need to load it + f.write('\t{name} = cast(typeof({name}))load("{name}");\n' + .format(name=func.proto.name)) + f.write('\treturn;\n') + f.write('}\n') + + written.add(ext.name) + + f.write('\n} /* private */\n\n') + + self.write_packages(rfeatures, extensions) + + def write_packages(self, allfeatures, allextensions): + f = self._f_gl + + self.write_module(f, self.PACKAGE) + self.write_imports(f, [self.FUNCS, self.EXT, self.ENUMS, self.TYPES], False) + + for api, features in allfeatures.items(): + extensions = allextensions[api] + with open(self.make_path(api), 'w') as f: + self.write_module(f, api) + + self.write_imports(f, [self.TYPES], False) + + extenums = chain.from_iterable(ext.enums for ext in extensions) + funcenums = chain.from_iterable(ext.enums for ext in extensions) + enums = set(enum.name for enum in extenums) | \ + set(enum.name for enum in funcenums) + + featfuncs = set(func.proto.name for func in + chain.from_iterable(feat.functions for feat in features)) + extfuncs = set(func.proto.name for func in + chain.from_iterable(ext.functions for ext in extensions)) + extfuncs = extfuncs - featfuncs + + enums |= set(enum.name for enum in + chain.from_iterable(feat.enums for feat in features)) + + self.write_selective_import(f, self.FUNCS, featfuncs) + self.write_selective_import(f, self.EXT, extfuncs) + self.write_selective_import(f, self.ENUMS, enums) + + + def generate_types(self, types): + f = self._f_types + + self.write_module(f, self.TYPES) + + f.write(self.TYPE_DICT.get('__pre', {}).get(self.spec.NAME,'')) + for ogl, d in self.TYPE_DICT[self.spec.NAME].items(): + self.write_alias(f, ogl, d) + self.TYPE_DICT['__other'][self.spec.NAME](self, f) + + def generate_features(self, features): + self.write_enums(features) + self.write_funcs(features) + + def write_enums(self, features): + e = self._f_enums + + self.write_module(e, self.ENUMS) + self.write_imports(e, [self.TYPES]) + + for v in self.TYPE_DICT['SpecialNumbers'][self.spec.NAME]: + self.write_enum(e, *v) + + written = set() + for feature in features: + for enum in feature.enums: + if enum.group == 'SpecialNumbers': + written.add(enum) + continue + if not enum in written: + self.write_enum(e, enum.name, enum.value) + written.add(enum) + + def write_funcs(self, features): + f = self._f_funcs + + self.write_module(f, self.FUNCS) + self.write_imports(f, [self.TYPES]) + + if self.spec.NAME == 'gl': + for feature in features: + self.write_boolean(f, feature.name) + + if self.spec.NAME in ('egl', 'wgl'): + self.write_extern(f) + for feature in features: + for func in feature.functions: + self.write_function_def(f, func) + self.write_extern_end(f) + else: + self.write_functions(f, set(), set(), features) + + def generate_extensions(self, extensions, enums, functions): + f = self._f_exts + + self.write_module(f, self.EXT) + self.write_imports(f, [self.TYPES, self.ENUMS, self.FUNCS]) + + write = set() + written = set(enum.name for enum in enums) | \ + set(function.proto.name for function in functions) + for ext in extensions: + if self.spec.NAME == 'gl' and not ext.name in written: + self.write_boolean(f, ext.name) + for enum in ext.enums: + if not enum.name in written and not enum.group == 'SpecialNumbers': + self.write_enum(self._f_enums, enum.name, enum.value) + written.add(enum.name) + written.add(ext.name) + + self.write_functions(f, write, written, extensions) + + def write_functions(self, f, write, written, extensions): + self.write_prototype_pre(f) + for ext in extensions: + for func in ext.functions: + if not func.proto.name in written: + self.write_function_prototype(f, func) + write.add(func) + written.add(func.proto.name) + self.write_prototype_post(f) + + self.write_function_pre(f) + for func in write: + self.write_function(f, func) + self.write_function_post(f) + + + def make_path(self, name): + path = os.path.join(self.path, self.MODULE.split('.')[-1], + self.spec.NAME, name.split('.')[-1] + self.FILE_EXTENSION) + makefiledir(path) + return path + + def write_imports(self, fobj, modules, private=True): + raise NotImplementedError + + def write_selective_import(self, fobj, imports): + raise NotImplementedError + + def write_module(self, fobj, name): + raise NotImplementedError + + def write_prototype_pre(self, fobj): + raise NotImplementedError + + def write_prototype_post(self, fobj): + raise NotImplementedError + + def write_function_pre(self, fobj): + raise NotImplementedError + + def write_function_post(self, fobj): + raise NotImplementedError + + def write_extern(self, fobj): + raise NotImplementedError + + def write_extern_end(self, fobj): + raise NotImplementedError + + def write_shared(self, fobj): + raise NotImplementedError + + def write_shared_end(self, fobj): + raise NotImplementedError + + def write_function_def(self, fobj, func): + raise NotImplementedError + + def write_function(self, fobj, func): + raise NotImplementedError + + def write_function_prototype(self, fobj, func): + raise NotImplementedError + + def write_boolean(self, fobj, name, value=False): + raise NotImplementedError + + def write_enum(self, fobj, name, value, type='uint'): + raise NotImplementedError + + def write_opaque_struct(self, fobj, name): + raise NotImplementedError + + def write_alias(self, fobj, newn, decl): + raise NotImplementedError + + +class DGenerator(BaseDGenerator): + MODULE = 'glad' + LOADER = 'loader' + ENUMS = 'enums' + EXT = 'ext' + FUNCS = 'funcs' + TYPES = 'types' + FILE_EXTENSION = '.d' + TYPE_DICT = DTYPES + + LOAD_GL_PREFIX = 'glad' + + def write_imports(self, fobj, modules, private=True): + for mod in modules: + if private: + fobj.write('private ') + else: + fobj.write('public ') + + fobj.write('import {}.{}.{};\n'.format(self.MODULE, self.spec.NAME, mod)) + + def write_selective_import(self, fobj, mod, imports): + if len(imports) == 0: return + + fobj.write('public import {}.{}.{} :\n'.format(self.MODULE, self.spec.NAME, mod)) + imports = set(imports) + last = len(imports) + for i, im in enumerate(imports, 1): + fobj.write(im) + if not i == last: + fobj.write(', ') + if (i % 5) == 0: + fobj.write('\n') + fobj.write(';\n\n') + + def write_module(self, fobj, name): + fobj.write('module {}.{}.{};\n\n\n'.format(self.MODULE, self.spec.NAME, name)) + + def write_prototype_pre(self, fobj): + fobj.write('nothrow @nogc ') + self.write_extern(fobj) + + def write_prototype_post(self, fobj): + self.write_extern_end(fobj) + + def write_function_pre(self, fobj): + self.write_shared(fobj) + + def write_function_post(self, fobj): + self.write_shared_end(fobj) + + def write_extern(self, fobj): + fobj.write('extern(System) {\n') + + def write_extern_end(self, fobj): + fobj.write('}\n') + + def write_shared(self, fobj): + fobj.write('__gshared {\n') + + def write_shared_end(self, fobj): + fobj.write('}\n') + + def write_function_def(self, fobj, func): + fobj.write('{} {}('.format(func.proto.ret.to_d(), func.proto.name)) + fobj.write(', '.join(param.type.to_d() for param in func.params)) + fobj.write(');\n') + + def write_function(self, fobj, func): + fobj.write('fp_{0} {0};\n'.format(func.proto.name)) + + def write_function_prototype(self, fobj, func): + fobj.write('alias fp_{} = {} function(' + .format(func.proto.name, func.proto.ret.to_d())) + fobj.write(', '.join(param.type.to_d() for param in func.params)) + fobj.write(');\n') + + def write_boolean(self, fobj, name, value=False): + if value: + fobj.write('bool {} = true;\n'.format(name)) + else: + fobj.write('bool {};\n'.format(name)) + + def write_enum(self, fobj, name, value, type='uint'): + if isinstance(value, basestring) and '"' in value: + type = 'const(char)*' + + fobj.write('enum {} {} = {};\n'.format(type, name, value)) + + def write_opaque_struct(self, fobj, name): + fobj.write('struct _{name}; alias {name} = _{name}*;\n'.format(name=name)) + + def write_alias(self, fobj, newn, decl): + fobj.write('alias {} = {};\n'.format(newn, decl)) + diff --git a/libs/glad/glad/lang/d/loader/__init__.py b/libs/glad/glad/lang/d/loader/__init__.py @@ -0,0 +1,90 @@ + +LOAD_OPENGL_DLL = ''' +version(Windows) { + private import core.sys.windows.windows; +} else { + private import core.sys.posix.dlfcn; +} + +version(Windows) { + private __gshared HMODULE libGL; +} else { + private __gshared void* libGL; +} +extern(System) private @nogc alias gladGetProcAddressPtrType = void* function(const(char)*); +private __gshared gladGetProcAddressPtrType gladGetProcAddressPtr; + +%(pre)s +bool %(init)s() @nogc { + version(Windows) { + libGL = LoadLibraryA("opengl32.dll"); + if(libGL !is null) { + gladGetProcAddressPtr = cast(typeof(gladGetProcAddressPtr))GetProcAddress( + libGL, "wglGetProcAddress"); + return gladGetProcAddressPtr !is null; + } + + return false; + } else { + version(OSX) { + enum const(char)*[] NAMES = [ + "../Frameworks/OpenGL.framework/OpenGL", + "/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" + ]; + } else { + enum const(char)*[] NAMES = ["libGL.so.1", "libGL.so"]; + } + + foreach(name; NAMES) { + libGL = dlopen(name, RTLD_NOW | RTLD_GLOBAL); + if(libGL !is null) { + version(OSX) { + return true; + } else { + gladGetProcAddressPtr = cast(typeof(gladGetProcAddressPtr))dlsym(libGL, + "glXGetProcAddressARB"); + return gladGetProcAddressPtr !is null; + } + } + } + + return false; + } +} + +%(pre)s +void* %(proc)s(const(char)* namez) @nogc { + if(libGL is null) return null; + void* result; + + if(gladGetProcAddressPtr !is null) { + result = gladGetProcAddressPtr(namez); + } + if(result is null) { + version(Windows) { + result = GetProcAddress(libGL, namez); + } else { + result = dlsym(libGL, namez); + } + } + + return result; +} + +%(pre)s +void %(terminate)s() @nogc { + version(Windows) { + if(libGL !is null) { + FreeLibrary(libGL); + libGL = null; + } + } else { + if(libGL !is null) { + dlclose(libGL); + libGL = null; + } + } +} +'''+ \ No newline at end of file diff --git a/libs/glad/glad/lang/d/loader/egl.py b/libs/glad/glad/lang/d/loader/egl.py @@ -0,0 +1,39 @@ +from glad.lang.common.loader import BaseLoader + + +_EGL_LOADER = ''' +bool gladLoadEGL() { + return gladLoadEGL(x => eglGetProcAddress(x)); +} +''' + +_EGL_HAS_EXT = ''' +private bool has_ext(const(char)* ext) @nogc { + return true; +} +''' + + +class EGLDLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('alias Loader = void* delegate(const(char)*);\n') + if not self.disabled: + fobj.write(_EGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn true;\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_EGL_HAS_EXT) diff --git a/libs/glad/glad/lang/d/loader/gl.py b/libs/glad/glad/lang/d/loader/gl.py @@ -0,0 +1,118 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.d.loader import LOAD_OPENGL_DLL + + +_OPENGL_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'private', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +bool gladLoadGL() { + bool status = false; + + if(open_gl()) { + status = gladLoadGL(x => get_proc(x)); + close_gl(); + } + + return status; +} +''' + +_OPENGL_HAS_EXT = ''' +static struct GLVersion { static int major = 0; static int minor = 0; } +private extern(C) char* strstr(const(char)*, const(char)*) @nogc; +private extern(C) int strcmp(const(char)*, const(char)*) @nogc; +private extern(C) int strncmp(const(char)*, const(char)*, size_t) @nogc; +private extern(C) size_t strlen(const(char)*) @nogc; +private bool has_ext(const(char)* ext) @nogc { + if(GLVersion.major < 3) { + const(char)* extensions = cast(const(char)*)glGetString(GL_EXTENSIONS); + const(char)* loc; + const(char)* terminator; + + if(extensions is null || ext is null) { + return false; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc is null) { + return false; + } + + terminator = loc + strlen(ext); + if((loc is extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\\0')) { + return true; + } + extensions = terminator; + } + } else { + int num; + glGetIntegerv(GL_NUM_EXTENSIONS, &num); + + for(uint i=0; i < cast(uint)num; i++) { + if(strcmp(cast(const(char)*)glGetStringi(GL_EXTENSIONS, i), ext) == 0) { + return true; + } + } + } + + return false; +} +''' + +_FIND_VERSION = ''' + // Thank you @elmindreda + // https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + // https://github.com/glfw/glfw/blob/master/src/context.c#L36 + int i; + const(char)* glversion; + const(char)*[] prefixes = [ + "OpenGL ES-CM ".ptr, + "OpenGL ES-CL ".ptr, + "OpenGL ES ".ptr, + ]; + + glversion = cast(const(char)*)glGetString(GL_VERSION); + if (glversion is null) return; + + foreach(prefix; prefixes) { + size_t length = strlen(prefix); + if (strncmp(glversion, prefix, length) == 0) { + glversion += length; + break; + } + } + + int major = glversion[0] - \'0\'; + int minor = glversion[2] - \'0\'; + GLVersion.major = major; GLVersion.minor = minor; +''' + + +class OpenGLDLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('alias Loader = void* delegate(const(char)*);\n') + if not self.disabled and 'gl' in self.apis: + fobj.write(_OPENGL_LOADER) + + def write_begin_load(self, fobj): + fobj.write('\tglGetString = cast(typeof(glGetString))load("glGetString");\n') + fobj.write('\tif(glGetString is null) { return false; }\n') + fobj.write('\tif(glGetString(GL_VERSION) is null) { return false; }\n\n') + + def write_end_load(self, fobj): + fobj.write('\treturn GLVersion.major != 0 || GLVersion.minor != 0;\n') + + def write_find_core(self, fobj): + fobj.write(_FIND_VERSION) + + def write_has_ext(self, fobj): + fobj.write(_OPENGL_HAS_EXT) + diff --git a/libs/glad/glad/lang/d/loader/glx.py b/libs/glad/glad/lang/d/loader/glx.py @@ -0,0 +1,49 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.d.loader import LOAD_OPENGL_DLL + + +_GLX_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'private', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +bool gladLoadGLX() { + bool status = false; + + if(open_gl()) { + status = gladLoadGLX(x => get_proc(x)); + close_gl(); + } + + return status; +} +''' + +_GLX_HAS_EXT = ''' +private bool has_ext(const(char)* name) @nogc { + return true; +} +''' + + +class GLXDLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('alias Loader = void* delegate(const(char)*);\n') + if not self.disabled: + fobj.write(_GLX_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn true;\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_GLX_HAS_EXT) diff --git a/libs/glad/glad/lang/d/loader/wgl.py b/libs/glad/glad/lang/d/loader/wgl.py @@ -0,0 +1,36 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.d.loader.glx import _GLX_LOADER + + +_WGL_LOADER = _GLX_LOADER.replace('GLX', 'WGL') + +_WGL_HAS_EXT = ''' +private bool has_ext(const(char)* name) @nogc { + return true; +} +''' + + +class WGLDLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('alias Loader = void* delegate(const(char)*);\n') + if not self.disabled: + fobj.write(_WGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn true;\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_WGL_HAS_EXT) diff --git a/libs/glad/glad/lang/nim/__init__.py b/libs/glad/glad/lang/nim/__init__.py @@ -0,0 +1,27 @@ +from glad.lang.nim.loader.egl import EGLNimLoader +from glad.lang.nim.loader.gl import OpenGLNimLoader +from glad.lang.nim.loader.glx import GLXNimLoader +from glad.lang.nim.loader.wgl import WGLNimLoader + +from glad.lang.nim.generator import NimGenerator + + +# TODO finish converting the egl, glx & wgl loaders to Nim + +_specs = { +# 'egl': EGLNimLoader, + 'gl': OpenGLNimLoader +# 'glx': GLXNimLoader, +# 'wgl': WGLNimLoader +} + +_generators = { + 'nim': NimGenerator, +} + + +def get_generator(name, spec): + gen = _generators.get(name) + loader = _specs.get(spec) + + return gen, loader diff --git a/libs/glad/glad/lang/nim/generator.py b/libs/glad/glad/lang/nim/generator.py @@ -0,0 +1,530 @@ +from itertools import chain +import os.path +import sys + +from glad.lang.common.generator import Generator +from glad.lang.common.util import makefiledir + + +if sys.version_info >= (3, 0): + from io import StringIO + basestring = str +else: + from StringIO import StringIO + + +def _gl_types(gen, f): + f.write(''' + GLdebugProc* = proc ( + source: GLenum, + typ: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} + + GLdebugProcArb* = proc ( + source: GLenum, + typ: GLenum, + id: GLuint, + severity: GLenum, + len: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} + + GLdebugProcAmd* = proc ( + id: GLuint, + category: GLenum, + severity: GLenum, + len: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} + + GLdebugProcKhr* = proc ( + source, typ: GLenum, + id: GLuint, + severity: GLenum, + length: GLsizei, + message: ptr GLchar, + userParam: pointer) {.stdcall.} +''') + + +# TODO finish converting the egl, glx & wgl loaders to Nim + +# def _egl_types(gen, f): +# def _glx_types(gen, f): +# def _wgl_types(gen, f): + +NIMTYPES = { + '__other': { + 'gl': _gl_types +# 'egl': _egl_types, +# 'glx': _glx_types, +# 'wgl': _wgl_types + }, + + 'gl': { + 'GLbitfield': 'uint32', + 'GLboolean': 'bool', + 'GLbyte': 'int8', + 'GLchar': 'char', + 'GLcharARB': 'byte', + 'GLclampd': 'float64', + 'GLclampf': 'float32', + 'GLclampx': 'int32', + 'GLdouble': 'float64', + 'GLeglImageOES': 'distinct pointer', + 'GLenum': 'uint32', + 'GLfixed': 'int32', + 'GLfloat': 'float32', + 'GLhalf': 'uint16', + 'GLhalfARB': 'uint16', + 'GLhalfNV': 'uint16', + 'GLhandleARB': 'uint32', + 'GLint': 'int32', + 'GLint64': 'int64', + 'GLint64EXT': 'int64', + 'GLintptr': 'int32', + 'GLintptrARB': 'int32', + 'GLshort': 'int16', + 'GLsizei': 'int32', + 'GLsizeiptr': 'int32', + 'GLsizeiptrARB': 'int32', + 'GLubyte': 'uint8', + 'GLuint': 'uint32', + 'GLuint64': 'uint64', + 'GLuint64EXT': 'uint64', + 'GLushort': 'uint16', + 'GLvdpauSurfaceNV': 'int32', + 'GLvoid': 'pointer', + 'GLsync': 'distinct pointer', + 'ClContext': 'distinct pointer', + 'ClEvent': 'distinct pointer' + }, + 'egl': { + 'EGLAttrib': 'int32', + 'EGLAttribKHR': 'int32', + 'EGLBoolean': 'bool', + 'EGLClientBuffer': 'distinct pointer', + 'EGLConfig': 'distinct pointer', + 'EGLContext': 'distinct pointer', + 'EGLDeviceEXT': 'distinct pointer', + 'EGLDisplay': 'distinct pointer', + 'EGLImage': 'distinct pointer', + 'EGLImageKHR': 'distinct pointer', + 'EGLNativeFileDescriptorKHR': 'int32', + 'EGLOutputLayerEXT': 'distinct pointer', + 'EGLOutputPortEXT': 'distinct pointer', + 'EGLStreamKHR': 'distinct pointer', + 'EGLSurface': 'distinct pointer', + 'EGLSync': 'distinct pointer', + 'EGLSyncKHR': 'distinct pointer', + 'EGLSyncNV': 'distinct pointer', + 'EGLTimeKHR': 'uint64', + 'EGLTime': 'uint64', + 'EGLTimeNV': 'uint64', + 'EGLenum': 'uint32', + 'EGLint': 'int32', + 'EGLsizeiANDROID': 'distinct pointer', + 'EGLuint64KHR': 'uint64', + 'EGLuint64MESA': 'uint64', + 'EGLuint64NV': 'uint64', +# '__eglMustCastToProperFunctionPointerType': 'void function()' + }, + 'glx': { + 'GLbitfield': 'uint32', + 'GLboolean': 'uint8', + 'GLenum': 'uint32', + 'GLfloat': 'float32', + 'GLint': 'int32', + 'GLintptr': 'int32', + 'GLsizei': 'int32', + 'GLsizeiptr': 'int32', + 'GLubyte': 'uint8', + 'GLuint': 'uint32' + }, + 'wgl': { + 'GLbitfield': 'uint32', + 'GLboolean': 'uint8', + 'GLenum': 'uint32', + 'GLfloat': 'float32', + 'GLint': 'int32', + 'GLsizei': 'int32', + 'GLuint': 'uint32', + 'GLushort': 'uint16', + 'INT32': 'int32', + 'INT64': 'int64' + }, + + 'SpecialNumbers': { + 'gl': [ + ('GL_FALSE', '0', None), + ('GL_INVALID_INDEX', '0xFFFFFFFF', 'uint32'), + ('GL_NONE', '0', None), + ('GL_NONE_OES', '0', None), + ('GL_NO_ERROR', '0', None), + ('GL_ONE', '1', None), + ('GL_TIMEOUT_IGNORED', '0xFFFFFFFFFFFFFFFF', 'uint64'), + ('GL_TIMEOUT_IGNORED_APPLE', '0xFFFFFFFFFFFFFFFF', 'uint64'), + ('GL_TRUE', '1', None), + ('GL_VERSION_ES_CL_1_0', '1', None), + ('GL_VERSION_ES_CL_1_1', '1', None), + ('GL_VERSION_ES_CM_1_1', '1', None), + ('GL_ZERO', '0', None), + ], + 'egl': [ +# ('EGL_DONT_CARE', '-1', 'int'), ('EGL_UNKNOWN', '-1', 'int'), +# ('EGL_NO_NATIVE_FENCE_FD_ANDROID', '-1', 'uint'), +# ('EGL_DEPTH_ENCODING_NONE_NV', '0', 'uint'), +# ('EGL_NO_CONTEXT', 'cast(EGLContext)0', 'EGLContext'), +# ('EGL_NO_DEVICE_EXT', 'cast(EGLDeviceEXT)0', 'EGLDeviceEXT'), +# ('EGL_NO_DISPLAY', 'cast(EGLDisplay)0', 'EGLDisplay'), +# ('EGL_NO_IMAGE', 'cast(EGLImage)0', 'EGLImage'), +# ('EGL_NO_IMAGE_KHR', 'cast(EGLImageKHR)0', 'EGLImageKHR'), +# ('EGL_DEFAULT_DISPLAY', 'cast(EGLNativeDisplayType)0', 'EGLNativeDisplayType'), +# ('EGL_NO_FILE_DESCRIPTOR_KHR', 'cast(EGLNativeFileDescriptorKHR)-1', 'EGLNativeFileDescriptorKHR'), +# ('EGL_NO_OUTPUT_LAYER_EXT', 'cast(EGLOutputLayerEXT)0', 'EGLOutputLayerEXT'), +# ('EGL_NO_OUTPUT_PORT_EXT', 'cast(EGLOutputPortEXT)0', 'EGLOutputPortEXT'), +# ('EGL_NO_STREAM_KHR', 'cast(EGLStreamKHR)0', 'EGLStreamKHR'), +# ('EGL_NO_SURFACE', 'cast(EGLSurface)0', 'EGLSurface'), +# ('EGL_NO_SYNC', 'cast(EGLSync)0', 'EGLSync'), +# ('EGL_NO_SYNC_KHR', 'cast(EGLSyncKHR)0', 'EGLSyncKHR'), +# ('EGL_NO_SYNC_NV', 'cast(EGLSyncNV)0', 'EGLSyncNV'), +# ('EGL_DISPLAY_SCALING', '10000', 'uint'), +# ('EGL_FOREVER', '0xFFFFFFFFFFFFFFFF', 'ulong'), +# ('EGL_FOREVER_KHR', '0xFFFFFFFFFFFFFFFF', 'ulong'), +# ('EGL_FOREVER_NV', '0xFFFFFFFFFFFFFFFF', 'ulong') + ], + 'glx': [ +# ('GLX_DONT_CARE', '0xFFFFFFFF', 'uint'), +# ('GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB', '0', 'uint') + ], + 'wgl': [ +# ('WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB', '0', 'uint'), +# ('WGL_FONT_LINES', '0', 'uint'), +# ('WGL_FONT_POLYGONS', 1, 'uint') + ] + }, + + 'SpecialEnumNames': { + 'gl': { + 'GL_BYTE': 'cGL_BYTE', + 'GL_SHORT': 'cGL_SHORT', + 'GL_INT': 'cGL_INT', + 'GL_FLOAT': 'cGL_FLOAT', + 'GL_DOUBLE': 'cGL_DOUBLE', + 'GL_FIXED': 'cGL_FIXED' + }, + 'egl': {}, + 'glx': {}, + 'wgl': {} + }, + + 'SpecialFuncNames': { + 'gl': { + 'glGetTransformFeedbacki_v': 'glGetTransformFeedbacki_v2' + }, + 'egl': {}, + 'glx': {}, + 'wgl': {} + } +} + + +class NimGenerator(Generator): + NAME = 'nim' + NAME_LONG = 'Nim' + + MODULE = 'glad' + FILE_EXTENSION = '.nim' + TYPE_DICT = NIMTYPES + + LOAD_GL_PREFIX = 'glad' + EXT_PREFIX = 'GLAD_' + + def open(self): + self._f_gl = open(self.make_path(self.spec.NAME), 'w') + + def close(self): + self._f_gl.close() + + def generate_header(self): + self._f_gl.write('#[') + self._f_gl.write(self.header) + self._f_gl.write(']#\n\n') + self._f_gl.write('import strutils\n\n') + self._f_gl.write('var glVersionMajor, glVersionMinor: int\n\n') + + def generate_loader(self, features, extensions): + f = self._f_gl + + rfeatures = features + if self.spec.NAME in ('egl', 'wgl'): + features = {'egl': [], 'wgl': []} + + self.loader.write(f) + self.loader.write_has_ext(f, self.get_version()) + + written = set() + for api, version in self.api.items(): + # core load procs + for feature in features[api]: + f.write('proc load_{}(load: proc) =\n' + .format(feature.name)) + if self.spec.NAME == 'gl': + f.write(' if not {}{}: return\n\n'.format(self.EXT_PREFIX, + feature.name)) + for func in feature.functions: + self.write_func_definition(f, func) + f.write('\n\n') + + # extension load procs + for ext in extensions[api]: + if len(list(ext.functions)) == 0 or ext.name in written: + continue + + f.write('proc load_{}(load: proc) =\n' + .format(ext.name)) + if self.spec.NAME == 'gl': + f.write(' if not {}{}: return\n'.format(self.EXT_PREFIX, + ext.name)) + for func in ext.functions: + # even if they were in written we need to load it + self.write_func_definition(f, func) + + f.write('\n\n') + + written.add(ext.name) + + # findExtensions proc + f.write('proc findExtensions{}() =\n'.format(api.upper())) + if self.spec.NAME == 'gl': + for ext in extensions[api]: + f.write(' {0}{1} = hasExt("{1}")\n'.format(self.EXT_PREFIX, + ext.name)) + f.write('\n\n') + + # findCore proc + f.write('proc findCore{}(glVersion: string) =\n'.format(api.upper())) + self.loader.write_find_core(f) + if self.spec.NAME == 'gl': + for feature in features[api]: + f.write(' {}{} = (major == {num[0]} and minor >= {num[1]}) or' + ' major > {num[0]}\n'.format(self.EXT_PREFIX, feature.name, + num=feature.number)) + f.write('\n\n') + + # main loader proc + loadername = 'Load' if self.LOAD_GL_PREFIX else 'load' + f.write('proc {}{}{}*(load: proc): bool =\n' + .format(self.LOAD_GL_PREFIX, loadername, api.upper())) + self.loader.write_begin_load(f) + + f.write(' findCore{}($glVersion)\n\n'.format(api.upper())) + for feature in features[api]: + f.write(' load_{}(load)\n'.format(feature.name)) + f.write('\n findExtensions{}()\n\n'.format(api.upper())) + for ext in extensions[api]: + if len(list(ext.functions)) == 0: + continue + f.write(' load_{}(load);\n'.format(ext.name)) + self.loader.write_end_load(f) + f.write('\n') + + + def write_func_definition(self, fobj, func): + func_name = self.map_func_name(func) + fobj.write(' {} = cast['.format(func_name)) + self.write_function_declaration(fobj, func) + fobj.write('](load("{}"))\n'.format(func_name)) + + + def map_func_name(self, func): + name = func.proto.name + m = self.TYPE_DICT['SpecialFuncNames'][self.spec.NAME] + return m[name] if name in m else name + + + def generate_types(self, types): + f = self._f_gl + + f.write('# Types\ntype\n') + for ogl, d in sorted(self.TYPE_DICT[self.spec.NAME].items()): + f.write(' {}* = {}\n'.format(ogl, d)) + self.TYPE_DICT['__other'][self.spec.NAME](self, f) + f.write('\n') + + + def generate_features(self, features): + self.write_enums(features) + self.write_funcs(features) + + + def write_enums(self, features): + f = self._f_gl + + f.write('\n# Enums\nconst\n') + for v in sorted(self.TYPE_DICT['SpecialNumbers'][self.spec.NAME]): + self.write_enum(f, *v) + f.write('\n') + + written = set() + for feature in features: + for enum in feature.enums: + if enum.group == 'SpecialNumbers': + written.add(enum) + continue + if not enum in written: + self.write_enum(f, enum.name, enum.value) + written.add(enum) + f.write('\n') + + + def write_funcs(self, features): + f = self._f_gl + + f.write('\n# Functions\nvar\n') + if self.spec.NAME == 'gl': + for feature in features: + self.write_boolean(f, feature.name) + f.write('\n') + + # TODO + if self.spec.NAME in ('egl', 'wgl'): + for feature in features: + for func in feature.functions: + self.write_function_def(f, func) # TODO + f.write('\n') + else: + self.write_functions(f, set(), set(), features) + f.write('\n\n') + + + # TODO + def write_function_def(self, fobj, func): + fobj.write('{} {}('.format(func.proto.ret.to_nim(), self.map_func_name(func))) + fobj.write(', '.join(param.type.to_nim() for param in func.params)) + fobj.write(');\n') + + + def generate_extensions(self, extensions, enums, functions): + f = self._f_gl + + write = set() + written = set(enum.name for enum in enums) | \ + set(function.proto.name for function in functions) + + f.write('# Extensions\nvar\n') + for ext in extensions: + if self.spec.NAME == 'gl' and not ext.name in written: + self.write_boolean(f, ext.name) + + for enum in ext.enums: + if not enum.name in written and not enum.group == 'SpecialNumbers': + type = (None if enum.group == 'TransformFeedbackTokenNV' + else 'GLenum') + self.write_enum(f, enum.name, enum.value, type) + written.add(enum.name) + written.add(ext.name) + f.write('\n') + + self.write_functions(f, write, written, extensions) + f.write('\n\n') + + + def write_functions(self, f, write, written, extensions): + for ext in extensions: + for func in ext.functions: + if not func.proto.name in written: + self.write_function_var(f, func) + write.add(func) + written.add(func.proto.name) + + + def write_function_var(self, fobj, func): + fobj.write(' {}*: '.format(self.map_func_name(func))) + self.write_function_declaration(fobj, func) + fobj.write('\n') + + + def write_function_declaration(self, fobj, func): + fobj.write('proc ('.format(self.map_func_name(func))) + fobj.write(', '.join('{}: {}'.format(self.to_nim_param_name(param.name), + param.type.to_nim()) + for param in func.params)) + fobj.write(')') + + ret = func.proto.ret.to_nim() + if (ret != 'void'): + fobj.write(': {}'.format(ret)) + + fobj.write(' {.cdecl.}') + +# TODO +# def write_function_var(self, fobj, func): +# fobj.write(' {} = cast[proc ('.format(func.proto.name)) +# fobj.write(', '.join('{}: {}'.format(self.to_nim_param_name(param.name), +# param.type.to_nim()) +# for param in func.params)) +# fobj.write(')') +# +# ret = func.proto.ret.to_nim() +# if (ret != 'void'): +# fobj.write(': {}'.format(ret)) +# +# fobj.write(' {.cdecl.}]') +# fobj.write(' (getProcAddress("{}"))\n'.format(func.proto.name)) + + + NIM_KEYWORDS = [ # as of Nim 0.13.0 + 'addr', 'and', 'as', 'asm', 'atomic', + 'bind', 'block', 'break', + 'case', 'cast', 'concept', 'const', 'continue', 'converter', + 'defer', 'discard', 'distinct', 'div', 'do', + 'elif', 'else', 'end', 'enum', 'except', 'export', + 'finally', 'for', 'from', 'func', + 'generic', + 'if', 'import', 'in', 'include', 'interface', 'is', 'isnot', 'iterator', + 'let', + 'macro', 'method', 'mixin', 'mod', + 'nil', 'not', 'notin', + 'object', 'of', 'or', 'out', + 'proc', 'ptr', + 'raise', 'ref', 'return', + 'shl', 'shr', 'static', + 'template', 'try', 'tuple', 'type', + 'using', + 'var', + 'when', 'while', 'with', 'without', + 'xor', + 'yield' + ] + + def to_nim_param_name(self, name): + return '`{}`'.format(name) if name in self.NIM_KEYWORDS else name + + def make_path(self, name): + path = os.path.join(self.path, self.MODULE.split('.')[-1], + name.split('.')[-1] + self.FILE_EXTENSION) + makefiledir(path) + return path + + def write_boolean(self, fobj, name): + fobj.write(' {}{}*: bool\n'.format(self.EXT_PREFIX, name)) + + def write_enum(self, fobj, name, value, type='GLenum'): + fobj.write(' {}*'.format(self.map_enum_name(name))) + if type: + fobj.write(': {0} = {0}({1})'.format(type, value)) + else: + fobj.write(' = {}'.format(value)) + fobj.write('\n') + + def map_enum_name(self, name): + m = self.TYPE_DICT['SpecialEnumNames'][self.spec.NAME] + return m[name] if name in m else name + + def get_version(self): + return self.api[self.spec.NAME] diff --git a/libs/glad/glad/lang/nim/loader/__init__.py b/libs/glad/glad/lang/nim/loader/__init__.py @@ -0,0 +1,90 @@ + +LOAD_OPENGL_DLL = ''' +version(Windows) { + private import std.c.windows.windows; +} else { + private import core.sys.posix.dlfcn; +} + +version(Windows) { + private __gshared HMODULE libGL; +} else { + private __gshared void* libGL; +} +extern(System) private @nogc alias gladGetProcAddressPtrType = void* function(const(char)*); +private __gshared gladGetProcAddressPtrType gladGetProcAddressPtr; + +%(pre)s +bool %(init)s() @nogc { + version(Windows) { + libGL = LoadLibraryA("opengl32.dll"); + if(libGL !is null) { + gladGetProcAddressPtr = cast(typeof(gladGetProcAddressPtr))GetProcAddress( + libGL, "wglGetProcAddress"); + return gladGetProcAddressPtr !is null; + } + + return false; + } else { + version(OSX) { + enum const(char)*[] NAMES = [ + "../Frameworks/OpenGL.framework/OpenGL", + "/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" + ]; + } else { + enum const(char)*[] NAMES = ["libGL.so.1", "libGL.so"]; + } + + foreach(name; NAMES) { + libGL = dlopen(name, RTLD_NOW | RTLD_GLOBAL); + if(libGL !is null) { + version(OSX) { + return true; + } else { + gladGetProcAddressPtr = cast(typeof(gladGetProcAddressPtr))dlsym(libGL, + "glXGetProcAddressARB"); + return gladGetProcAddressPtr !is null; + } + } + } + + return false; + } +} + +%(pre)s +void* %(proc)s(const(char)* namez) @nogc { + if(libGL is null) return null; + void* result; + + if(gladGetProcAddressPtr !is null) { + result = gladGetProcAddressPtr(namez); + } + if(result is null) { + version(Windows) { + result = GetProcAddress(libGL, namez); + } else { + result = dlsym(libGL, namez); + } + } + + return result; +} + +%(pre)s +void %(terminate)s() @nogc { + version(Windows) { + if(libGL !is null) { + FreeLibrary(libGL); + libGL = null; + } + } else { + if(libGL !is null) { + dlclose(libGL); + libGL = null; + } + } +} +'''+ \ No newline at end of file diff --git a/libs/glad/glad/lang/nim/loader/egl.py b/libs/glad/glad/lang/nim/loader/egl.py @@ -0,0 +1,40 @@ +from glad.lang.common.loader import BaseLoader + + +# TODO this is just a quick initial conversion of the D loader + +_EGL_LOADER = ''' +bool gladLoadEGL() { + return gladLoadEGL(x => eglGetProcAddress(x)) +} +''' + +_EGL_HAS_EXT = ''' +private bool has_ext(const(char)* ext) @nogc { + return true +} +''' + + +class EGLNimLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + if not self.disabled: + fobj.write(_EGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write(' return true\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_EGL_HAS_EXT) diff --git a/libs/glad/glad/lang/nim/loader/gl.py b/libs/glad/glad/lang/nim/loader/gl.py @@ -0,0 +1,147 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.nim.loader import LOAD_OPENGL_DLL + + +_OPENGL_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'private', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +bool gladLoadGL() + bool status = false + + if(open_gl()) + status = gladLoadGL(x => get_proc(x)) + close_gl() + + return status + +''' + +_OPENGL_HAS_EXT_LT3 = '''proc hasExt(extname: string): bool = + if extname == nil: + return false + + var extensions = $cast[cstring](glGetString(GL_EXTENSIONS)) + if extensions == nil: + return false + + var + loc, terminatorLoc: int + terminator: char + + while true: + loc = extensions.find(extname) + if loc < 0: + return false + + terminatorLoc = loc + extname.len + terminator = extensions[terminatorLoc] + + if (loc == 0 or extensions[loc - 1] == ' ') and + (terminator == ' ' or terminator == '\\0'): + return true + + extensions = extensions[terminatorLoc..^1] + + +''' + +_OPENGL_HAS_EXT_GTE3 = '''proc hasExt(extname: string): bool = + if extname == nil: + return false + + if glVersionMajor < 3: + var extensions = $cast[cstring](glGetString(GL_EXTENSIONS)) + if extensions == nil: + return false + + var + loc, terminatorLoc: int + terminator: char + + while true: + loc = extensions.find(extname) + if loc < 0: + return false + + terminatorLoc = loc + extname.len + terminator = extensions[terminatorLoc] + + if (loc == 0 or extensions[loc - 1] == ' ') and + (terminator == ' ' or terminator == '\\0'): + return true + + extensions = extensions[terminatorLoc..^1] + + else: + var + num: GLint + s: cstring + + glGetIntegerv(GL_NUM_EXTENSIONS, num.addr) + + for i in 0..num-1: + s = cast[cstring](glGetStringi(GL_EXTENSIONS, GLuint(i))) + if s == extname: + return true + + +''' + +_FIND_VERSION = ''' # Thank you @elmindreda + # https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + # https://github.com/glfw/glfw/blob/master/src/context.c#L36 + var prefixes = ["OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES "] + + var version = glVersion + for p in prefixes: + if version.startsWith(p): + version = version.replace(p) + break + + var major = ord(glVersion[0]) - ord('0') + var minor = ord(glVersion[2]) - ord('0') + + glVersionMajor = major + glVersionMinor = minor + +''' + +_BEGIN_LOAD = ''' glGetString = cast[proc (name: GLenum): ptr GLubyte {.cdecl.}](load("glGetString")) + if glGetString == nil: return false + + var glVersion = cast[cstring](glGetString(GL_VERSION)) + if glVersion == nil: return false + +''' + +class OpenGLNimLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + pass + # TODO +# if not self.disabled and 'gl' in self.apis: +# fobj.write(_OPENGL_LOADER) + + def write_begin_load(self, fobj): + fobj.write(_BEGIN_LOAD) + + def write_end_load(self, fobj): + fobj.write('\n return glVersionMajor != 0 or glVersionMinor != 0\n') + + def write_find_core(self, fobj): + fobj.write(_FIND_VERSION) + + def write_has_ext(self, fobj, apiversion): + if apiversion.major == 1 and apiversion.minor == 0: + return + if apiversion.major < 3: + fobj.write(_OPENGL_HAS_EXT_LT3) + else: + fobj.write(_OPENGL_HAS_EXT_GTE3) + + diff --git a/libs/glad/glad/lang/nim/loader/glx.py b/libs/glad/glad/lang/nim/loader/glx.py @@ -0,0 +1,51 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.nim.loader import LOAD_OPENGL_DLL + + +# TODO this is just a quick initial conversion of the D loader + +_GLX_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'private', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +bool gladLoadGLX() { + bool status = false + + if(open_gl()) { + status = gladLoadGLX(x => get_proc(x)) + close_gl() + } + + return status +} +''' + +_GLX_HAS_EXT = ''' +private bool has_ext(const(char)* name) @nogc { + return true +} +''' + + +class GLXNimLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('alias Loader = void* delegate(const(char)*)\n') + if not self.disabled: + fobj.write(_GLX_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write(' return true\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_GLX_HAS_EXT) diff --git a/libs/glad/glad/lang/nim/loader/wgl.py b/libs/glad/glad/lang/nim/loader/wgl.py @@ -0,0 +1,38 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.nim.loader.glx import _GLX_LOADER + + +# TODO this is just a quick initial conversion of the D loader + +_WGL_LOADER = _GLX_LOADER.replace('GLX', 'WGL') + +_WGL_HAS_EXT = ''' +private bool has_ext(const(char)* name) @nogc { + return true; +} +''' + + +class WGLNimLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('alias Loader = void* delegate(const(char)*);\n') + if not self.disabled: + fobj.write(_WGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write(' return true\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_WGL_HAS_EXT) diff --git a/libs/glad/glad/lang/volt/__init__.py b/libs/glad/glad/lang/volt/__init__.py @@ -0,0 +1,25 @@ +from glad.lang.volt.loader.egl import EGLVoltLoader +from glad.lang.volt.loader.gl import OpenGLVoltLoader +from glad.lang.volt.loader.glx import GLXVoltLoader +from glad.lang.volt.loader.wgl import WGLVoltLoader + +from glad.lang.volt.generator import VoltGenerator + + +_specs = { + 'egl': EGLVoltLoader, + 'gl': OpenGLVoltLoader, + 'glx': GLXVoltLoader, + 'wgl': WGLVoltLoader +} + +_generators = { + 'volt': VoltGenerator, +} + + +def get_generator(name, spec): + gen = _generators.get(name) + loader = _specs.get(spec) + + return gen, loader diff --git a/libs/glad/glad/lang/volt/generator.py b/libs/glad/glad/lang/volt/generator.py @@ -0,0 +1,86 @@ +import sys + +from glad.lang.d.generator import DGenerator + + +if sys.version_info >= (3, 0): + basestring = str + + +class VoltGenerator(DGenerator): + NAME = 'volt' + NAME_LONG = 'Volt' + + MODULE = 'amp' + LOADER = 'loader' + ENUMS = 'enums' + EXT = 'ext' + FUNCS = 'funcs' + TYPES = 'types' + FILE_EXTENSION = '.volt' + API = '' + + LOAD_GL_NAME = 'load' + + @property + def PACKAGE(self): + return 'package' + + def write_module(self, fobj, name): + if name == 'package': + fobj.write('module {}.{};\n\n'.format(self.MODULE, self.spec.NAME)) + else: + DGenerator.write_module(self, fobj, name) + + def write_prototype_pre(self, fobj): + fobj.write('extern(System) @loadDynamic {\n') + + def write_prototype_post(self, fobj): + fobj.write('}\n') + + def write_function_pre(self, fobj): + pass + + def write_function_post(self, fobj): + pass + + def write_shared(self, fobj): + fobj.write('global {\n') + + def write_shared_end(self, fobj): + fobj.write('}\n') + + def write_function(self, fobj, func): + pass + + def write_function_prototype(self, fobj, func): + fobj.write('{} {}(' + .format(func.proto.ret.to_volt(), func.proto.name)) + fobj.write(', '.join(param.type.to_volt() for param in func.params)) + fobj.write(');\n') + + def write_boolean(self, fobj, name, **kwargs): + fobj.write('global bool {};\n'.format(name)) + + def write_enum(self, fobj, name, value, type_='uint'): + if isinstance(value, basestring): + if value.startswith('0x') and type_.startswith('u'): + value += 'U' + if len(value) > 12 and type_.startswith('u'): + value += 'L' + + try: + v = int(value) + if v < 0: + type_ = 'int' + except ValueError: + pass + + if isinstance(value, basestring) and '"' in value: + type_ = 'const(char)*' + + fobj.write('enum {} {} = {};\n'.format(type_, name, value)) + + def write_opaque_struct(self, fobj, name): + fobj.write('struct _{name} {{}}\nalias {name} = _{name}*;\n'.format(name=name)) + diff --git a/libs/glad/glad/lang/volt/loader/__init__.py b/libs/glad/glad/lang/volt/loader/__init__.py @@ -0,0 +1,64 @@ + +LOAD_OPENGL_DLL = ''' +private global Library libGL; +extern(System) private alias gladGetProcAddressPtrType = void* function(const(char)*); +private global gladGetProcAddressPtrType gladGetProcAddressPtr; + +%(pre)s +bool %(init)s() { + version(Windows) { + libGL = Library.load("opengl32.dll"); + } else version(OSX) { + libGL = Library.loads([ + "../Frameworks/OpenGL.framework/OpenGL", + "/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" + ]); + } else { + libGL = Library.loads(["libGL.so.1", "libGL.so"]); + } + + if(libGL !is null) { + version(Windows) { + string sym = "wglGetProcAddress"; + } else { + string sym = "glXGetProcAddressARB"; + } + // returns null on OSX, but that's fine + gladGetProcAddressPtr = cast(typeof(gladGetProcAddressPtr))libGL.symbol(sym); + return true; + } + + return false; +} + +private struct StructToDg { + void* instance; + void* func; +} + +%(pre)s +void* %(proc)s(string name) { + if(libGL is null) return null; + void* result; + + if(gladGetProcAddressPtr !is null) { + // TODO: name.ptr + result = gladGetProcAddressPtr(name.ptr); + } + if(result is null) { + result = libGL.symbol(name); + } + + return result; +} + +%(pre)s +void %(terminate)s() { + if(libGL !is null) { + libGL.free(); + } + return; +} +'''+ \ No newline at end of file diff --git a/libs/glad/glad/lang/volt/loader/egl.py b/libs/glad/glad/lang/volt/loader/egl.py @@ -0,0 +1,48 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.d.loader.egl import _EGL_HAS_EXT as _D_EGL_HAS_EXT + + +_EGL_LOADER = ''' +private struct StructToDg { + void* instance; + void* func; +} + +private void* get_proc(string name) { + return eglGetProcAddress(arg.ptr); +} + +bool gladLoadEGL() { + StructToDg structToDg; + structToDg.func = cast(void*)get_proc; + auto dg = *cast(Loader*)&structToDg; + + return gladLoadEGL(dg); +} +''' +_EGL_HAS_EXT = _D_EGL_HAS_EXT + + +class EGLVoltLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('import watt.library;\n') + if not self.disabled: + fobj.write(_EGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn true;') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_EGL_HAS_EXT)+ \ No newline at end of file diff --git a/libs/glad/glad/lang/volt/loader/gl.py b/libs/glad/glad/lang/volt/loader/gl.py @@ -0,0 +1,60 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.volt.loader import LOAD_OPENGL_DLL +from glad.lang.d.loader.gl import _OPENGL_HAS_EXT as _D_OPENGL_HAS_EXT + + +_OPENGL_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'private', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +bool gladLoadGL() { + StructToDg structToDg; + structToDg.func = cast(void*)get_proc; + auto dg = *cast(Loader*)&structToDg; + + bool status = false; + + if(open_gl()) { + status = gladLoadGL(dg); + close_gl(); + } + + return status; +} +''' + +_OPENGL_HAS_EXT = ( + 'global int GL_MAJOR = 0;\nglobal int GL_MINOR = 0;' + + '\n'.join(l for l in _D_OPENGL_HAS_EXT.replace('@nogc', '').splitlines() if 'struct' not in l) + .replace('GLVersion.major', 'GL_MAJOR') + + '\n\n' +) + + +class OpenGLVoltLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('import watt.library;\n') + if not self.disabled and 'gl' in self.apis: + fobj.write(_OPENGL_LOADER) + + def write_begin_load(self, fobj): + fobj.write('\tglGetString = cast(typeof(glGetString))load("glGetString");\n') + fobj.write('\tif(glGetString is null) { return false; }\n') + fobj.write('\tif(glGetString(GL_VERSION) is null) { return false; }\n\n') + + def write_end_load(self, fobj): + fobj.write('\treturn GL_MAJOR != 0 || GL_MINOR != 0;\n') + + def write_find_core(self, fobj): + fobj.write('\tconst(char)* v = cast(const(char)*)glGetString(GL_VERSION);\n') + fobj.write('\tint major = v[0] - \'0\';\n') + fobj.write('\tint minor = v[2] - \'0\';\n') + fobj.write('\tGL_MAJOR = major; GL_MINOR = minor;\n') + + def write_has_ext(self, fobj): + fobj.write(_OPENGL_HAS_EXT)+ \ No newline at end of file diff --git a/libs/glad/glad/lang/volt/loader/glx.py b/libs/glad/glad/lang/volt/loader/glx.py @@ -0,0 +1,47 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.volt.loader import LOAD_OPENGL_DLL + + +_GLX_LOADER = \ + LOAD_OPENGL_DLL % {'pre':'private', 'init':'open_gl', + 'proc':'get_proc', 'terminate':'close_gl'} + ''' +bool gladLoadGLX() { + StructToDg structToDg; + structToDg.func = cast(void*)get_proc; + auto dg = *cast(Loader*)&structToDg; + + bool status = false; + + if(open_gl()) { + status = gladLoadGLX(dg); + close_gl(); + } + + return status; +} +''' + +_GLX_HAS_EXT = ''' +private bool has_ext(const(char)* name) { + return true; +} +''' + + +class GLXVoltLoader(BaseLoader): + def write(self, fobj): + fobj.write('import watt.library;\n') + if not self.disabled: + fobj.write(_GLX_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn true;\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_GLX_HAS_EXT)+ \ No newline at end of file diff --git a/libs/glad/glad/lang/volt/loader/wgl.py b/libs/glad/glad/lang/volt/loader/wgl.py @@ -0,0 +1,35 @@ +from glad.lang.common.loader import BaseLoader +from glad.lang.volt.loader.glx import _GLX_LOADER + + +_WGL_LOADER = _GLX_LOADER.replace('GLX', 'WGL') +_WGL_HAS_EXT = ''' +private bool has_ext(const(char)* name) { + return true; +} +''' + + +class WGLVoltLoader(BaseLoader): + def write_header_end(self, fobj): + pass + + def write_header(self, fobj): + pass + + def write(self, fobj): + fobj.write('import watt.library;\n') + if not self.disabled: + fobj.write(_WGL_LOADER) + + def write_begin_load(self, fobj): + pass + + def write_end_load(self, fobj): + fobj.write('\treturn true;\n') + + def write_find_core(self, fobj): + pass + + def write_has_ext(self, fobj): + fobj.write(_WGL_HAS_EXT)+ \ No newline at end of file diff --git a/libs/glad/glad/opener.py b/libs/glad/glad/opener.py @@ -0,0 +1,112 @@ +from contextlib import closing +import logging +import sys + +if sys.version_info >= (3, 0): + _is_py3 = True + from urllib.request import build_opener, ContentTooShortError +else: + _is_py3 = False + from urllib2 import build_opener + from urllib import FancyURLopener + + +logger = logging.getLogger('glad.opener') + + +def build_urllib_opener(user_agent, *args, **kwargs): + if _is_py3: + return None + + class UrllibURLOpener(FancyURLopener): + version = user_agent + return UrllibURLOpener(*args, **kwargs) + + +def _urlretrieve_with_opener(opener, url, filename, data=None): + if not _is_py3: + raise SyntaxError('Only call this in Python 3 code.') + + # borrowed from the original implementation at urllib.request.urlretrieve. + with closing(opener.open(url, data=data)) as src: + headers = src.info() + + with open(filename, 'wb') as dest: + result = filename, headers + bs = 1024*8 + size = -1 + read = 0 + blocknum = 0 + if "content-length" in headers: + size = int(headers["Content-Length"]) + + while True: + block = src.read(bs) + if not block: + break + read += len(block) + dest.write(block) + blocknum += 1 + + if size >= 0 and read < size: + raise ContentTooShortError( + 'retrieval incomplete: got only %i out of %i bytes' + % (read, size), result) + + return result + + +class URLOpener(object): + """ + Class to download/find Khronos related files, like + the official specs and khrplatform.h. + + Can also be used to download files, exists mainly because of + Python 2 and Python 3 incompatibilities. + """ + def __init__(self, user_agent='Mozilla/5.0'): + # the urllib2/urllib.request opener + self.opener = build_opener() + self.opener.addheaders = [('User-agent', user_agent)] + + # the urllib opener (Python 2 only) + self.opener2 = build_urllib_opener(user_agent) + + def urlopen(self, url, data=None, *args, **kwargs): + """ + Same as urllib2.urlopen or urllib.request.urlopen, + the only difference is that it links to the internal opener. + """ + logger.info('opening: \'%s\'', url) + + if data is None: + return self.opener.open(url) + + return self.opener.open(url, data) + + def urlretrieve(self, url, filename, data=None): + """ + Similar to urllib.urlretrieve or urllib.request.urlretrieve + only that *filname* is required. + + :param url: URL to download. + :param filename: Filename to save the content to. + :param data: Valid URL-encoded data. + :return: Tuple containing path and headers. + """ + logger.info('saving: \'%s\' to \'%s\'', url, filename) + + if _is_py3: + return _urlretrieve_with_opener(self.opener, url, filename, data=data) + + return self.opener2.retrieve(url, filename, data=data) + + # just a singleton helper: + _default = None + + @classmethod + def default(cls): + if cls._default is None: + cls._default = cls() + + return cls._default diff --git a/libs/glad/glad/parse.py b/libs/glad/glad/parse.py @@ -0,0 +1,356 @@ +try: + from lxml import etree + from lxml.etree import ETCompatXMLParser as parser + + def xml_fromstring(argument): + return etree.fromstring(argument, parser=parser()) + + def xml_frompath(path): + return etree.parse(path, parser=parser()).getroot() +except ImportError: + try: + import xml.etree.cElementTree as etree + except ImportError: + import xml.etree.ElementTree as etree + + def xml_fromstring(argument): + return etree.fromstring(argument) + + def xml_frompath(path): + return etree.parse(path).getroot() + + +from collections import defaultdict, OrderedDict +from contextlib import closing +from itertools import chain +import re + +from glad.opener import URLOpener + + +_ARRAY_RE = re.compile(r'\[\d*\]') + + +class Spec(object): + API = 'https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/' + NAME = '' + + def __init__(self, root): + self.root = root + + self._types = None + self._groups = None + self._enums = None + self._commands = None + self._features = None + self._extensions = None + + @classmethod + def from_url(cls, url, opener=None): + if opener is None: + opener = URLOpener.default() + + with closing(opener.urlopen(url)) as f: + raw = f.read() + + return cls(xml_fromstring(raw)) + + @classmethod + def from_svn(cls, opener=None): + return cls.from_url(cls.API + cls.NAME + '.xml', opener=opener) + + @classmethod + def fromstring(cls, string): + return cls(xml_fromstring(string)) + + @classmethod + def from_file(cls, path): + return cls(xml_frompath(path)) + + @property + def comment(self): + return self.root.find('comment').text + + @property + def types(self): + if self._types is None: + self._types = [Type(element) for element in + self.root.find('types').iter('type')] + return self._types + + @property + def groups(self): + if self._groups is None: + self._groups = dict([(element.attrib['name'], Group(element)) + for element in self.root.find('groups')]) + return self._groups + + @property + def commands(self): + if self._commands is None: + self._commands = dict([(element.find('proto').find('name').text, + Command(element, self)) + for element in self.root.find('commands')]) + return self._commands + + @property + def enums(self): + if self._enums is not None: + return self._enums + + self._enums = dict() + for element in self.root.iter('enums'): + namespace = element.attrib['namespace'] + type_ = element.get('type') + group = element.get('group') + vendor = element.get('vendor') + comment = element.get('comment', '') + + for enum in element: + if enum.tag == 'unused': + continue + assert enum.tag == 'enum' + + name = enum.attrib['name'] + self._enums[name] = Enum(name, enum.attrib['value'], namespace, + type_, group, vendor, comment) + + return self._enums + + @property + def features(self): + if self._features is not None: + return self._features + + self._features = defaultdict(OrderedDict) + for element in self.root.iter('feature'): + num = tuple(map(int, element.attrib['number'].split('.'))) + self._features[element.attrib['api']][num] = Feature(element, self) + + return self._features + + @property + def extensions(self): + if self._extensions is not None: + return self._extensions + + self._extensions = defaultdict(dict) + for element in self.root.find('extensions'): + for api in element.attrib['supported'].split('|'): + self._extensions[api][element.attrib['name']] = Extension(element, self) + + return self._extensions + + +class Type(object): + def __init__(self, element): + apientry = element.find('apientry') + if apientry is not None: + apientry.text = 'APIENTRY' + self.raw = ''.join(element.itertext()) + self.api = element.get('api') + self.name = element.get('name') + + @property + def is_preprocessor(self): + return '#' in self.raw + + +class Group(object): + def __init__(self, element): + self.name = element.attrib['name'] + self.enums = [enum.attrib['name'] for enum in element] + + +class Enum(object): + def __init__(self, name, value, namespace, type_=None, + group=None, vendor=None, comment=''): + self.name = name + self.value = value + self.namespace = namespace + self.type = type_ + self.group = group + self.vendor = vendor + self.comment = comment + + def __hash__(self): + return hash(self.name) + + def __str__(self): + return self.name + + __repr__ = __str__ + + +class Command(object): + def __init__(self, element, spec): + self.proto = Proto(element.find('proto')) + self.params = [Param(ele, spec) for ele in element.iter('param')] + + def __hash__(self): + return hash(self.proto.name) + + def __str__(self): + return '{self.proto.name}'.format(self=self) + + __repr__ = __str__ + + +class Proto(object): + def __init__(self, element): + self.name = element.find('name').text + self.ret = OGLType(element) + + def __str__(self): + return '{self.ret} {self.name}'.format(self=self) + + +class Param(object): + def __init__(self, element, spec): + self.group = element.get('group') + self.type = OGLType(element) + self.name = element.find('name').text.strip('*') + + def __str__(self): + return '{0!r} {1}'.format(self.type, self.name) + + +class OGLType(object): + def __init__(self, element): + self.element = element + self.raw = ''.join(element.itertext()).strip() + + self.name = element.find('name').text + + self.type = (self.raw.replace('const', '').replace('unsigned', '') + .replace('struct', '').strip().split(None, 1)[0] + if element.find('ptype') is None else element.find('ptype').text) + # 0 if no pointer, 1 if *, 2 if ** + self.is_pointer = 0 if self.raw is None else self.raw.count('*') + # it can be a pointer to an array, or just an array + self.is_pointer += len(_ARRAY_RE.findall(self.raw)) + self.is_const = False if self.raw is None else 'const' in self.raw + self.is_unsigned = False if self.raw is None else 'unsigned' in self.raw + + if 'struct' in self.raw and 'struct' not in self.type: + self.type = 'struct {}'.format(self.type) + + ptype = element.find('ptype') + self.ptype = ptype.text if ptype is not None else None + + def to_d(self): + if self.is_pointer > 1 and self.is_const: + s = 'const({}{}*)'.format('u' if self.is_unsigned else '', self.type) + s += '*' * (self.is_pointer - 1) + else: + t = '{}{}'.format('u' if self.is_unsigned else '', self.type) + s = 'const({})'.format(t) if self.is_const else t + s += '*' * self.is_pointer + return s.replace('struct ', '') + + to_volt = to_d + + def to_c(self): + result = '' + for text in self.element.itertext(): + if text == self.name: + # yup * is sometimes part of the name + result += '*' * text.count('*') + else: + result += text + result = _ARRAY_RE.sub('*', result) + return result.strip() + + NIM_POINTER_MAP = { + 'void': 'pointer', + 'GLchar': 'cstring', + 'struct _cl_context': 'ClContext', + 'struct _cl_event': 'ClEvent' + } + + def to_nim(self): + if self.is_pointer == 2: + s = 'cstringArray' if self.type == 'GLchar' else 'ptr pointer' + else: + s = self.type + if self.is_pointer == 1: + default = 'ptr ' + s + s = self.NIM_POINTER_MAP.get(s, default) + return s + + __str__ = to_d + __repr__ = __str__ + + +class Extension(object): + def __init__(self, element, spec): + self.name = element.attrib['name'] + + self.require = [] + for required in chain.from_iterable(element.findall('require')): + if required.tag == 'type': + continue + + data = {'enum': spec.enums, 'command': spec.commands}[required.tag] + try: + self.require.append(data[required.attrib['name']]) + except KeyError: + pass # TODO + + @property + def enums(self): + for r in self.require: + if isinstance(r, Enum): + yield r + + @property + def functions(self): + for r in self.require: + if isinstance(r, Command): + yield r + + def __hash__(self): + return hash(self.name) + + def __str__(self): + return self.name + + __repr__ = __str__ + + +class Feature(Extension): + def __init__(self, element, spec): + Extension.__init__(self, element, spec) + self.spec = spec + + # not every spec has a ._remove member, but there shouldn't be a remove + # tag without that member, if there is, blame me! + for removed in chain.from_iterable(element.findall('remove')): + if removed.tag == 'type': + continue + + data = {'enum': spec.enums, 'command': spec.commands}[removed.tag] + try: + spec._remove.add(data[removed.attrib['name']]) + except KeyError: + pass # TODO + + self.number = tuple(map(int, element.attrib['number'].split('.'))) + self.api = element.attrib['api'] + + def __str__(self): + return '{self.name}@{self.number!r}'.format(self=self) + + @property + def enums(self): + for enum in super(Feature, self).enums: + if enum not in getattr(self.spec, 'removed', []): + yield enum + + @property + def functions(self): + for func in super(Feature, self).functions: + if func not in getattr(self.spec, 'removed', []): + yield func + + __repr__ = __str__ diff --git a/libs/glad/glad/spec.py b/libs/glad/glad/spec.py @@ -0,0 +1,50 @@ +from glad.parse import Spec + + +class EGLSpec(Spec): + NAME = 'egl' + + +class GLSpec(Spec): + NAME = 'gl' + + def __init__(self, root): + Spec.__init__(self, root) + + self._profile = 'compatibility' + self._remove = set() + + @property + def profile(self): + return self._profile + + @profile.setter + def profile(self, value): + if value not in ('core', 'compatibility'): + raise ValueError('profile must either be core or compatibility') + + self._profile = value + + @property + def removed(self): + if self._profile == 'core': + return frozenset(self._remove) + return frozenset() + + +class GLXSpec(Spec): + NAME = 'glx' + + +class WGLSpec(Spec): + NAME = 'wgl' + + +SPECS = dict() + +# reflection to fill SPECS +import sys +import inspect +for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): + if issubclass(cls, Spec): + SPECS[cls.NAME] = cls diff --git a/libs/glad/glad/util.py b/libs/glad/glad/util.py @@ -0,0 +1,14 @@ +_API_NAMES = { + 'egl': 'EGL', + 'gl': 'OpenGL', + 'gles1': 'OpenGL ES', + 'gles2': 'OpenGL ES', + 'glx': 'GLX', + 'wgl': 'WGL', +} + + +def api_name(api): + api = api.lower() + return _API_NAMES[api] + diff --git a/libs/glad/main.py b/libs/glad/main.py @@ -0,0 +1,9 @@ +from glad.__main__ import main +import warnings + +warnings.simplefilter('always', DeprecationWarning) +_message = 'main.py is deprecated, use "python -m glad" instead ' \ + 'or install glad via pip, see README.md for more information.' +warnings.warn(_message, DeprecationWarning, stacklevel=1) + +main() diff --git a/scripts/glad.sh b/scripts/glad.sh @@ -0,0 +1,11 @@ +#! /bin/sh + +set -e + +cd libs/glad +python -m glad --profile=core --api=gl=3.3 --generator=c --spec=gl --out-path gladout --omit-khrplatform \ + --extensions GL_KHR_debug,GL_EXT_texture_sRGB,GL_EXT_texture_compression_s3tc,GL_EXT_texture_compression_rgtc +mv gladout/src/glad.c ../../glad.cc +mv gladout/include/glad/glad.h ../../glad.h +rm -r gladout +sed -i "s/#include <glad\\/glad\\.h>/#include \"glad.h\"/" ../../glad.cc