generator.py (12020B)
1 import os 2 import sys 3 4 from glad.lang.common.generator import Generator 5 from glad.lang.common.util import makefiledir 6 7 8 KHRPLATFORM = 'https://www.khronos.org/registry/egl/api/KHR/khrplatform.h' 9 10 11 class CGenerator(Generator): 12 NAME = 'c' 13 NAME_LONG = 'C/C++' 14 15 def open(self): 16 suffix = '' 17 if not self.spec.NAME == 'gl': 18 suffix = '_{}'.format(self.spec.NAME) 19 20 if self.local_files: 21 self.h_include = '"glad{}.h"'.format(suffix) 22 self._f_c = open(make_path(self.path, 23 'glad{}.c'.format(suffix)), 'w') 24 self._f_h = open(make_path(self.path, 25 'glad{}.h'.format(suffix)), 'w') 26 khr = self.path 27 else: 28 self.h_include = '<glad/glad{}.h>'.format(suffix) 29 self._f_c = open(make_path(self.path, 'src', 30 'glad{}.c'.format(suffix)), 'w') 31 self._f_h = open(make_path(self.path, 'include', 'glad', 32 'glad{}.h'.format(suffix)), 'w') 33 khr = os.path.join(self.path, 'include', 'KHR') 34 35 if not self.omit_khrplatform: 36 khr_url = KHRPLATFORM 37 if os.path.exists('khrplatform.h'): 38 khr_url = 'file://' + os.path.abspath('khrplatform.h') 39 40 khrplatform = os.path.join(khr, 'khrplatform.h') 41 if not os.path.exists(khrplatform): 42 if not os.path.exists(khr): 43 os.makedirs(khr) 44 self.opener.urlretrieve(khr_url, khrplatform) 45 46 return self 47 48 def close(self): 49 self._f_c.close() 50 self._f_h.close() 51 52 def generate_header(self): 53 self._f_h.write('/*\n') 54 self._f_h.write(self.header) 55 self._f_h.write('*/\n\n') 56 57 self._f_c.write('/*\n') 58 self._f_c.write(self.header) 59 self._f_c.write('*/\n\n') 60 61 def generate_loader(self, features, extensions): 62 f = self._f_c 63 64 if self.spec.NAME in ('egl', 'wgl'): 65 features = {'egl': [], 'wgl': []} 66 67 written = set() 68 for api, version in self.api.items(): 69 for feature in features[api]: 70 f.write('static void load_{}(GLADloadproc load) {{\n' 71 .format(feature.name)) 72 if self.spec.NAME in ('gl', 'glx', 'wgl'): 73 f.write('\tif(!GLAD_{}) return;\n'.format(feature.name)) 74 for func in feature.functions: 75 f.write('\tglad_{0} = (PFN{1}PROC)load("{0}");\n' 76 .format(func.proto.name, func.proto.name.upper())) 77 f.write('}\n') 78 79 for ext in extensions[api]: 80 if len(list(ext.functions)) == 0 or ext.name in written: 81 continue 82 83 f.write('static void load_{}(GLADloadproc load) {{\n' 84 .format(ext.name)) 85 if self.spec.NAME in ('gl', 'glx', 'wgl'): 86 f.write('\tif(!GLAD_{}) return;\n'.format(ext.name)) 87 if ext.name == 'GLX_SGIX_video_source': f.write('#ifdef _VL_H_\n') 88 if ext.name == 'GLX_SGIX_dmbuffer': f.write('#ifdef _DM_BUFFER_H_\n') 89 for func in ext.functions: 90 # even if they were in written we need to load it 91 f.write('\tglad_{0} = (PFN{1}PROC)load("{0}");\n' 92 .format(func.proto.name, func.proto.name.upper())) 93 if ext.name in ('GLX_SGIX_video_source', 'GLX_SGIX_dmbuffer'): 94 f.write('#else\n') 95 f.write('\t(void)load;\n') 96 f.write('#endif\n') 97 f.write('}\n') 98 99 written.add(ext.name) 100 101 f.write('static int find_extensions{}(void) {{\n'.format(api.upper())) 102 if self.spec.NAME in ('gl', 'glx', 'wgl'): 103 f.write('\tif (!get_exts()) return 0;\n') 104 for ext in extensions[api]: 105 f.write('\tGLAD_{0} = has_ext("{0}");\n'.format(ext.name)) 106 f.write('\tfree_exts();\n') 107 f.write('\treturn 1;\n') 108 f.write('}\n\n') 109 110 if api == 'glx': 111 f.write('static void find_core{}(Display *dpy, int screen) {{\n'.format(api.upper())) 112 elif api == 'wgl': 113 f.write('static void find_core{}(HDC hdc) {{\n'.format(api.upper())) 114 else: 115 f.write('static void find_core{}(void) {{\n'.format(api.upper())) 116 117 self.loader.write_find_core(f) 118 if self.spec.NAME in ('gl', 'glx', 'wgl'): 119 for feature in features[api]: 120 f.write('\tGLAD_{} = (major == {num[0]} && minor >= {num[1]}) ||' 121 ' major > {num[0]};\n'.format(feature.name, num=feature.number)) 122 if self.spec.NAME == 'gl': 123 f.write('\tif (GLVersion.major > {0} || (GLVersion.major >= {0} && GLVersion.minor >= {1})) {{\n'.format(version[0], version[1])) 124 f.write('\t\tmax_loaded_major = {0};\n'.format(version[0])) 125 f.write('\t\tmax_loaded_minor = {0};\n'.format(version[1])) 126 f.write('\t}\n') 127 f.write('}\n\n') 128 129 if api == 'glx': 130 f.write('int gladLoad{}Loader(GLADloadproc load, Display *dpy, int screen) {{\n'.format(api.upper())) 131 elif api == 'wgl': 132 f.write('int gladLoad{}Loader(GLADloadproc load, HDC hdc) {{\n'.format(api.upper())) 133 else: 134 f.write('int gladLoad{}Loader(GLADloadproc load) {{\n'.format(api.upper())) 135 136 self.loader.write_begin_load(f) 137 138 if api == 'glx': 139 f.write('\tfind_core{}(dpy, screen);\n'.format(api.upper())) 140 elif api == 'wgl': 141 f.write('\tfind_core{}(hdc);\n'.format(api.upper())) 142 else: 143 f.write('\tfind_core{}();\n'.format(api.upper())) 144 145 for feature in features[api]: 146 f.write('\tload_{}(load);\n'.format(feature.name)) 147 f.write('\n\tif (!find_extensions{}()) return 0;\n'.format(api.upper())) 148 for ext in extensions[api]: 149 if len(list(ext.functions)) == 0: 150 continue 151 f.write('\tload_{}(load);\n'.format(ext.name)) 152 153 self.loader.write_end_load(f) 154 f.write('}\n\n') 155 156 self.loader.write_header_end(self._f_h) 157 158 def generate_types(self, types): 159 f = self._f_h 160 161 self.loader.write_header(f) 162 self.write_api_header(f) 163 164 for type in types: 165 output_string = (type.raw + '\n').lstrip().replace(' ', ' ') 166 if output_string == '#include <KHR/khrplatform.h>\n': 167 if self.omit_khrplatform: 168 continue 169 elif self.local_files: 170 output_string = '#include "khrplatform.h"\n' 171 if not self.spec.NAME in ('egl',) and 'khronos' in type.raw: 172 continue 173 f.write(output_string) 174 175 def generate_features(self, features): 176 f = self._f_h 177 write = set() 178 if self.spec.NAME in ('wgl',): 179 # These are already defined in windows.h 180 pass 181 elif self.spec.NAME in ('egl',): 182 self.write_enums(f, set(), features) 183 184 for feature in features: 185 for func in feature.functions: 186 self.write_function_def(f, func) 187 else: 188 self.write_functions(f, write, set(), features) 189 190 f = self._f_c 191 self.write_code_head(f) 192 self.loader.write(f) 193 self.loader.write_has_ext(f) 194 195 if self.spec.NAME in ('gl', 'glx', 'wgl'): 196 for feature in features: 197 f.write('int GLAD_{};\n'.format(feature.name)) 198 199 for func in write: 200 self.write_function(f, func) 201 202 def generate_extensions(self, extensions, enums, functions): 203 write = set() 204 written = set(enum.name for enum in enums) | \ 205 set(function.proto.name for function in functions) 206 207 f = self._f_h 208 self.write_functions(f, write, written, extensions) 209 210 f = self._f_c 211 if self.spec.NAME in ('gl', 'glx', 'wgl'): 212 for ext in set(ext.name for ext in extensions): 213 f.write('int GLAD_{};\n'.format(ext)) 214 215 written = set() 216 for ext in extensions: 217 if ext.name == 'GLX_SGIX_video_source': f.write('#ifdef _VL_H_\n') 218 if ext.name == 'GLX_SGIX_dmbuffer': f.write('#ifdef _DM_BUFFER_H_\n') 219 for func in ext.functions: 220 if func in write and func not in written: 221 self.write_function(f, func) 222 written.add(func) 223 if ext.name in ('GLX_SGIX_video_source', 'GLX_SGIX_dmbuffer'): f.write('#endif\n') 224 225 def write_functions(self, f, write, written, extensions): 226 self.write_enums(f, written, extensions) 227 228 for ext in extensions: 229 f.write('#ifndef {0}\n#define {0} 1\n'.format(ext.name)) 230 if self.spec.NAME in ('gl', 'glx', 'wgl'): 231 f.write('GLAPI int GLAD_{};\n'.format(ext.name)) 232 if ext.name == 'GLX_SGIX_video_source': f.write('#ifdef _VL_H_\n') 233 if ext.name == 'GLX_SGIX_dmbuffer': f.write('#ifdef _DM_BUFFER_H_\n') 234 for func in ext.functions: 235 if not func.proto.name in written: 236 self.write_function_prototype(f, func) 237 write.add(func) 238 written.add(func.proto.name) 239 if ext.name in ('GLX_SGIX_video_source', 'GLX_SGIX_dmbuffer'): f.write('#endif\n') 240 f.write('#endif\n') 241 242 def write_enums(self, f, written, extensions): 243 for ext in extensions: 244 for enum in ext.enums: 245 if not enum.name in written: 246 f.write('#define {} {}\n'.format(enum.name, enum.value)) 247 written.add(enum.name) 248 249 def write_api_header(self, f): 250 for api in self.api: 251 if api == 'glx': 252 f.write('GLAPI int gladLoad{}Loader(GLADloadproc, Display *dpy, int screen);\n\n'.format(api.upper())) 253 elif api == 'wgl': 254 f.write('GLAPI int gladLoad{}Loader(GLADloadproc, HDC hdc);\n\n'.format(api.upper())) 255 else: 256 f.write('GLAPI int gladLoad{}Loader(GLADloadproc);\n\n'.format(api.upper())) 257 258 def write_code_head(self, f): 259 f.write('#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include {}\n'.format(self.h_include)) 260 261 def write_extern(self, fobj): 262 fobj.write('#ifdef __cplusplus\nextern "C" {\n#endif\n') 263 264 def write_extern_end(self, fobj): 265 fobj.write('#ifdef __cplusplus\n}\n#endif\n') 266 267 def write_function_def(self, fobj, func): 268 # write a function definition instead of a prototype. 269 # e.g. egl uses that, since the main functions get linked in and not loaded through a function. 270 fobj.write('{}('.format(func.proto.ret.raw)) 271 fobj.write(', '.join(param.type.raw for param in func.params)) 272 fobj.write(');\n') 273 274 def write_function_prototype(self, fobj, func): 275 fobj.write('typedef {} (APIENTRYP PFN{}PROC)({});\n'.format( 276 func.proto.ret.to_c(), func.proto.name.upper(), 277 ', '.join(param.type.raw for param in func.params)) 278 ) 279 fobj.write('GLAPI PFN{}PROC glad_{};\n'.format(func.proto.name.upper(), 280 func.proto.name)) 281 fobj.write('#define {0} glad_{0}\n'.format(func.proto.name)) 282 283 def write_function(self, fobj, func): 284 fobj.write('PFN{}PROC glad_{};\n'.format(func.proto.name.upper(), 285 func.proto.name)) 286 287 288 def make_path(path, *args): 289 path = os.path.join(path, *args) 290 makefiledir(path) 291 return path