orca/scripts/glapi.py

254 lines
7.0 KiB
Python
Raw Normal View History

import xml.etree.ElementTree as et
from argparse import ArgumentParser
from datetime import datetime
#---------------------------------------------------------------
#NOTE: get args
#---------------------------------------------------------------
parser = ArgumentParser()
parser.add_argument("-s", "--spec")
parser.add_argument("-d", "--directory")
args = parser.parse_args()
apiName = 'gl_api'
loaderName = 'gl_loader'
apiPath = args.directory + '/' + apiName + '.h'
loaderHeaderPath = args.directory + '/' + loaderName + '.h'
loaderCPath = args.directory + '/' + loaderName + '.c'
#---------------------------------------------------------------
#NOTE: gather all GL functions in GL 4.1, 4.3, and GLES 3.0 and 3.1
#---------------------------------------------------------------
def gather_api(tree, api, version):
procs = []
for feature in tree.iterfind('feature[@api="'+ api +'"]'):
if float(feature.get('number')) > version:
break
for require in feature.iter('require'):
if require.get('profile') == 'compatibility':
continue
for command in require.iter('command'):
procs.append(command.get('name'))
for remove in feature.iter('remove'):
for command in remove.iter('command'):
procs.remove(command.get('name'))
return(procs)
tree = et.parse(args.spec)
# put all GL commands in a dict
commands = dict()
commandsSpec = tree.find('./commands')
for command in commandsSpec.iter('command'):
name = command.find('proto/name')
commands[name.text] = command
#gather command names per API
gl41 = gather_api(tree, 'gl', 4.1)
gl43 = gather_api(tree, 'gl', 4.3)
gl44 = gather_api(tree, 'gl', 4.4)
gles31 = gather_api(tree, 'gles2', 3.1)
gles32 = gather_api(tree, 'gles2', 3.2)
glall = list(set().union(gl41, gl43, gl44, gles31, gles32))
#---------------------------------------------------------------
# helpers
#---------------------------------------------------------------
def emit_doc(f, name, ext):
f.write("/********************************************************\n")
f.write("*\n")
f.write("*\t@file: " + name + ext + '\n')
f.write("*\t@note: auto-generated by glapi.py from gl.xml\n")
f.write("*\t@date: %s\n" % datetime.now().strftime("%d/%m%Y"))
f.write("*\n")
2023-02-20 10:05:01 +00:00
f.write("*********************************************************/\n")
def emit_begin_guard(f, name):
guard = '__' + name.upper() + '_H__'
f.write("#ifndef " + guard + "\n")
f.write("#define " + guard + "\n\n")
def emit_end_guard(f, name):
guard = '__' + name.upper() + '_H__'
f.write("#endif // " + guard + "\n")
def remove_prefix(s, prefix):
if s.startswith(prefix):
return s[len(prefix):]
#---------------------------------------------------------------
# Generate GL API header file
#---------------------------------------------------------------
f = open(apiPath, 'w')
emit_doc(f, apiName, '.h')
emit_begin_guard(f, apiName)
f.write('#include"GL/glcorearb.h"\n')
f.write('#include"GLES3/gl32.h"\n\n')
# generate interface struct
f.write('typedef struct mg_gl_api\n{\n')
f.write(' const char* name;\n')
for func in glall:
f.write('\t' + 'PFN' + func.upper() + 'PROC ' + remove_prefix(func, 'gl') + ';\n')
f.write('} mg_gl_api;\n\n')
# generate interface macros
# TODO guard for different api/versions and only #define functions present in desired version
f.write("MP_API mg_gl_api* mg_gl_get_api(void);\n\n")
for func in glall:
f.write('#define ' + func + ' mg_gl_get_api()->' + remove_prefix(func, 'gl') + '\n')
emit_end_guard(f, apiName)
f.close()
#---------------------------------------------------------------
# Generate GL loader header
#---------------------------------------------------------------
f = open(loaderHeaderPath, 'w')
emit_doc(f, loaderName, '.h')
emit_begin_guard(f, loaderName)
f.write('#include"gl_api.h"\n\n')
f.write("typedef void*(*mg_gl_load_proc)(const char* name);\n\n")
f.write("void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gl44(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc);\n\n")
f.write("void mg_gl_select_api(mg_gl_api* api);\n\n")
emit_end_guard(f, loaderName)
f.close()
#---------------------------------------------------------------
# Generate GL loader code
#---------------------------------------------------------------
def emit_loader(f, name, procs):
f.write('void mg_gl_load_'+ name +'(mg_gl_api* api, mg_gl_load_proc loadProc)\n')
f.write("{\n")
f.write(' api->name = "'+ name +'";\n')
for proc in glall:
if proc in procs:
f.write(' api->' + remove_prefix(proc, 'gl') + ' = loadProc("' + proc + '");\n')
else:
f.write(' api->' + remove_prefix(proc, 'gl') + ' = mg_' + proc + '_noimpl;\n')
f.write("}\n\n")
def emit_null_api(f, procs):
f.write('mg_gl_api __mgGLNoAPI;\n\n')
for name in procs:
command = commands.get(name)
if command == None:
print("Couldn't find definition for required command '" + name + "'")
exit(-1)
proto = command.find("proto")
ptype = proto.find("ptype")
retType = ''
if proto.text != None:
retType += proto.text
if ptype != None:
if ptype.text != None:
retType += ptype.text
if ptype.tail != None:
retType += ptype.tail
retType = retType.strip()
f.write(retType + ' mg_' + name + '_noimpl(')
params = command.findall('param')
for i, param in enumerate(params):
argName = param.find('name').text
typeNode = param.find('ptype')
typeName = ''
if param.text != None:
typeName += param.text
if typeNode != None:
if typeNode.text != None:
typeName += typeNode.text
if typeNode.tail != None:
typeName += typeNode.tail
typeName = typeName.strip()
f.write(typeName + ' ' + argName)
if i < len(params)-1:
f.write(', ')
f.write(')\n')
f.write('{\n')
f.write(' if(__mgGLAPI == &__mgGLNoAPI)\n')
f.write(' {\n')
f.write(' log_error("No GL or GLES API is selected. Make sure you call mg_surface_prepare() before calling OpenGL API functions.\\n");\n')
f.write(' }\n')
f.write(' else\n')
f.write(' {\n')
f.write(' log_error("'+ name +' is not part of currently selected %s API\\n", __mgGLAPI->name);\n')
f.write(' }\n')
if retType != 'void':
f.write(' return(('+ retType +')0);\n')
f.write('}\n')
f.write('mg_gl_api __mgGLNoAPI = {\n')
for proc in procs:
f.write(' .' + remove_prefix(proc, 'gl') + ' = mg_' + proc + '_noimpl,\n')
f.write("};\n\n")
f = open(loaderCPath, 'w')
emit_doc(f, loaderName, '.c')
2023-02-20 10:05:01 +00:00
f.write('#include"' + loaderName + '.h"\n')
f.write('#include"platform.h"\n\n')
f.write("mp_thread_local mg_gl_api* __mgGLAPI = 0;\n")
emit_null_api(f, glall)
emit_loader(f, 'gl41', gl41)
emit_loader(f, 'gl43', gl43)
emit_loader(f, 'gl44', gl44)
emit_loader(f, 'gles31', gles31)
emit_loader(f, 'gles32', gles32)
2023-02-20 18:38:24 +00:00
f.write("void mg_gl_select_api(mg_gl_api* api){ __mgGLAPI = api; }\n")
f.write("void mg_gl_deselect_api(){ __mgGLAPI = &__mgGLNoAPI; }\n")
2023-02-20 18:38:24 +00:00
f.write("mg_gl_api* mg_gl_get_api(void) { return(__mgGLAPI); }\n\n")
f.close()