X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=scripts%2Fextgen.py;h=4333cf37345f176d06fdf52abe2e6f30d8cc1f0c;hp=2c515f22ecee971f234796924428376d58f80c8f;hb=9705e1a5f1b6065c2cfa0cc987d65b332fdde5ce;hpb=aa6020a158c85fdb3b7e9993065861dd1b6531ad diff --git a/scripts/extgen.py b/scripts/extgen.py index 2c515f22..4333cf37 100755 --- a/scripts/extgen.py +++ b/scripts/extgen.py @@ -1,40 +1,256 @@ #!/usr/bin/python import sys +import os +import xml.dom +import xml.dom.minidom +import itertools -ext=sys.argv[1] - -funcs=[] -cur_func=None -for line in file("gl.spec"): - if line[0]=='#' or line.find(':')>=0: - continue - elif line[0]=='\t' and cur_func: - parts=line.split() - if parts[0]=="category" and parts[1]==ext: - funcs.append(cur_func) +### Command line processing ### + +if len(sys.argv)<2: + print """Usage: + extgen.py [] [ ...] + extgen.py [] + +Reads gl.xml and generates files to use . Any promoted functions +are exposed with their promoted names. If extensions are given, +any promoted functions from those are pulled in as well. can +be given to override the version where was promoted to core. + +In the second form, the parameters are read from . If is +absent, the extension's lowercased name is used. Anything after the last dot +in is removed and replaced with cpp and h.""" + sys.exit(0) + +ext = sys.argv[1] +out_base = None +if ext.endswith(".glext"): + fn = ext + ext = None + ver = None + secondary = [] + for line in open(fn): + parts = line.split() + if parts[0]=="extension": + ext = parts[1] + elif parts[0]=="core_version": + ver = parts[1] + elif parts[0]=="secondary": + secondary.append(parts[1]) + if len(sys.argv)>=3: + out_base = os.path.splitext(sys.argv[2])[0] +else: + secondary = sys.argv[2:] + ver = None + if secondary and secondary[0][0].isdigit(): + ver = secondary.pop(0) + +exttype = ext.split('_')[0] +backport_ext = None + +if not out_base: + out_base = ext.lower() + +### XML file parsing ### + +class Thing: + FUNCTION = 1 + ENUM = 2 + + def __init__(self, name, kind): + self.name = name + self.kind = kind + self.version = None + self.extension = None + self.aliases = [] + self.source = None + +class Function(Thing): + def __init__(self, name): + Thing.__init__(self, name, Thing.FUNCTION) + self.typedef = None + self.vectorequiv = None + +class Enum(Thing): + def __init__(self, name): + Thing.__init__(self, name, Thing.ENUM) + self.value = 0 + +things = {} + +def get_nested_elements(elem, path): + if '/' in path: + head, tail = path.split('/', 1) + result = [] + for e in elem.getElementsByTagName(head): + result += get_nested_elements(e, tail) + return result + else: + return elem.getElementsByTagName(path) + +def get_text_contents(node): + result = "" + for c in node.childNodes: + if c.nodeType==xml.dom.Node.TEXT_NODE or c.nodeType==xml.dom.Node.CDATA_SECTION_NODE: + result += c.data + else: + result += get_text_contents(c) + return result + +def parse_file(fn): + doc = xml.dom.minidom.parse(fn) + root = doc.documentElement + commands = get_nested_elements(root, "commands/command") + for cmd in commands: + name = get_text_contents(get_nested_elements(cmd, "proto/name")[0]) + func = things.get(name) + if not func: + func = Function(name) + things[name] = func + + aliases = cmd.getElementsByTagName("alias") + for a in aliases: + func.aliases.append(a.getAttribute("name")) + + vec = cmd.getElementsByTagName("vecequiv") + if vec: + func.vectorequiv = vec[0].getAttribute("name") + + enums = get_nested_elements(root, "enums/enum") + for en in enums: + name = en.getAttribute("name") + enum = things.get(name) + if not enum: + enum = Enum(name) + things[name] = enum + + enum.value = int(en.getAttribute("value"), 16) + + features = root.getElementsByTagName("feature") + for feat in features: + api = feat.getAttribute("api") + if api=="gl": + version = feat.getAttribute("number") + + commands = get_nested_elements(feat, "require/command") + enums = get_nested_elements(feat, "require/enum") + for t in itertools.chain(commands, enums): + name = t.getAttribute("name") + thing = things.get(name) + if thing: + thing.version = version + + if feat.getAttribute("name")=="MSPGL_REMOVE": + commands = get_nested_elements(feat, "remove/command") + enums = get_nested_elements(feat, "require/enum") + for t in itertools.chain(commands, enums): + name = t.getAttribute("name") + if name in things: + del things[name] + + extensions = get_nested_elements(root, "extensions/extension") + for ext in extensions: + ext_name = ext.getAttribute("name") + if ext_name.startswith("GL_"): + ext_name = ext_name[3:] + supported = ext.getAttribute("supported").split('|') + if "gl" in supported: + commands = get_nested_elements(ext, "require/command") + enums = get_nested_elements(ext, "require/enum") + for t in itertools.chain(commands, enums): + name = t.getAttribute("name") + thing = things.get(name) + if thing: + thing.extension = ext_name + +parse_file("gl.xml") +parse_file("gl.fixes.xml") + +### Additional processing ### + +# Find aliases for enums +enums = [t for t in things.itervalues() if t.kind==Thing.ENUM] +core_enums_by_value = dict((e.value, e) for e in enums if e.version) + +for e in enums: + if e.kind==t.ENUM and e.extension: + ce = core_enums_by_value.get(e.value) + if ce and ce!=e: + e.aliases.append(ce.name) + +# Create references from core things to their extension counterparts +for t in things.itervalues(): + if t.extension==ext or t.extension in secondary: + for a in t.aliases: + alias = things.get(a) + if alias: + alias.source = t + +def is_relevant(t): + # Unpromoted extension things are relevant + if t.extension==ext and not t.aliases: + return True + + # Core things promoted from the extension are also relevant + if t.source: + e = t.source + if e.extension==ext or e.extension in secondary: + return True + + return False + +funcs = [t for t in things.itervalues() if t.kind==Thing.FUNCTION and is_relevant(t)] +funcs.sort(key=(lambda f: f.name)) +enums = [e for e in enums if is_relevant(e)] +enums.sort(key=(lambda e: e.value)) + +for t in itertools.chain(funcs, enums): + if not ver: + ver = t.version + + # Things in backport extensions don't acquire an extension suffix + if t.extension and not t.name.endswith(exttype): + backport_ext = t.extension + +for f in funcs: + if f.source: + # Typedefs for early core functions are not available in all + # implementations + f.typedef = "PFN%sPROC"%f.source.name.upper() else: - paren=line.find('(') - if paren>0: - cur_func=line[:paren] + f.typedef = "PFN%sPROC"%f.name.upper() + +if ver: + ver = map(int, ver.split('.')) + +### Output ### -out=file(ext.lower()+".h", "w") +out = file(out_base+".h", "w") out.write("#ifndef MSP_GL_%s_\n"%ext.upper()) out.write("#define MSP_GL_%s_\n"%ext.upper()) out.write(""" -#include "gl.h" -#include +#include +#include namespace Msp { namespace GL { - """) -for f in funcs: - out.write("extern PFNGL%sPROC gl%s;\n"%(f.upper(), f)) +if funcs or enums: + out.write("\n#ifndef GL_%s\n"%ext) + for f in funcs: + out.write("typedef int (*%s)(...);\n"%f.typedef) + if funcs and enums: + out.write("\n") + for e in enums: + out.write("#define %s 0x%04X\n"%(e.name, e.value)) + out.write("#endif\n\n") + for f in funcs: + out.write("extern %s %s;\n"%(f.typedef, f.name)) -out.write("\nvoid init_%s();\n"%ext.lower()) +out.write("\nextern Extension %s;\n"%ext) out.write(""" } // namespace GL @@ -43,24 +259,45 @@ out.write(""" #endif """) -out=file(ext.lower()+".cpp", "w") -out.write("#include \"extension.h\"\n") +out = file(out_base+".cpp", "w") out.write("#include \"%s.h\"\n"%ext.lower()) out.write(""" namespace Msp { namespace GL { - """) +if funcs: + out.write("\n") for f in funcs: - out.write("PFNGL%sPROC gl%s=0;\n"%(f.upper(), f)) + out.write("%s %s = 0;\n"%(f.typedef, f.name)) -out.write("\nvoid init_%s()\n{\n"%ext.lower()) -for f in funcs: - out.write("\tgl%s=reinterpret_cast(get_proc_address(\"gl%s\"));\n"%(f, f.upper(), f)) +out.write("\nExtension::SupportLevel init_%s()\n{\n"%ext.lower()) +out.write("#ifdef GL_%s\n"%ext) +if ver: + out.write("\tif(is_version_at_least(%d, %d)"%tuple(ver)) + if backport_ext: + out.write(" || is_supported(\"GL_%s\")"%backport_ext) + out.write(")\n\t{\n") + for f in funcs: + out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, f.name)) + out.write("\t\treturn Extension::CORE;\n") + out.write("\t}\n") +if ext!=backport_ext: + out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(ext)) + for f in funcs: + n = f.name + if f.source: + n = f.source.name + out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, n)) + out.write("\t\treturn Extension::EXTENSION;\n") + out.write("\t}\n") +out.write("#endif\n") +out.write("\treturn Extension::UNSUPPORTED;\n") out.write("}\n") +out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(ext, ext, ext.lower())) + out.write(""" } // namespace GL } // namespace Msp