530 lines
17 KiB
Python
530 lines
17 KiB
Python
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]
|