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 = ''.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)) if len(extensions[api]) == 0: f.write('\t(void)&has_ext;\n') # suppress unused has_ext warnings 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 \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 if type.name in ('GLsizeiptr', 'GLintptr', 'GLsizeiptrARB', 'GLintptrARB'): # 10.6 is the last version supporting more than 64 bit (>1060) output_string = \ '#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) ' +\ '&& (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)\n' +\ output_string.replace('ptrdiff_t', 'long') + '#else\n' + output_string + '#endif\n' 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 \n#include \n#include \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