#!/usr/bin/python
import sys
+import os
+import xml.dom
+import xml.dom.minidom
-ext = sys.argv[1]
+if len(sys.argv)<2:
+ print """Usage:
+ extgen.py <extension> [<version>] [<secondary> ...]"
-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:
+Reads gl.spec and generates files to use <extension>. Any promoted functions
+are exposed with their promoted names. If <secondary> extensions are given,
+any promoted functions from those are pulled in as well. <version> can be
+given to override the version where <extension> was promoted to core."""
+ 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]=="category" and parts[1]==ext:
- funcs.append(cur_func)
+ 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]
+bp_ext = None
+
+if not out_base:
+ out_base = ext.lower()
+
+class Function:
+ def __init__(self, name):
+ self.name = name
+ self.typedef = None
+ self.version = None
+ self.category = None
+ self.vectorequiv = None
+ self.aliases = []
+ self.extfunc = None
+
+funcs = {}
+cur_func = None
+
+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:
- paren = line.find('(')
- if paren>0:
- cur_func = line[:paren]
+ 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 = funcs.get(name)
+ if not func:
+ func = Function(name)
+ funcs[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")
+
+ 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")
+ for c in commands:
+ name = c.getAttribute("name")
+ func = funcs.get(name)
+ if func:
+ func.version = version
+
+ if feat.getAttribute("name")=="MSPGL_REMOVE":
+ commands = get_nested_elements(feat, "remove/command")
+ for c in commands:
+ name = c.getAttribute("name")
+ if name in funcs:
+ del funcs[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")
+ for c in commands:
+ name = c.getAttribute("name")
+ func = funcs.get(name)
+ if func:
+ func.category = ext_name
+
+parse_file("gl.xml")
+parse_file("gl.fixes.xml")
+
+for f in funcs.itervalues():
+ if f.category==ext or f.category in secondary:
+ for a in f.aliases:
+ aliasfunc = funcs.get(a)
+ if aliasfunc:
+ aliasfunc.extfunc = f
+
+def is_relevant(f):
+ if f.category==ext and not f.aliases:
+ return True
+ if f.extfunc:
+ e = f.extfunc
+ if e.category==ext or e.category in secondary:
+ return True
+ return False
+
+funcs = [f for f in funcs.itervalues() if is_relevant(f)]
+funcs.sort(key=(lambda f: f.name))
+
+for f in funcs:
+ if not ver:
+ ver = f.version
+
+ if f.category and not f.name.endswith(exttype):
+ bp_ext = f.category
-out = file(ext.lower()+".h", "w")
+ if f.extfunc:
+ f.typedef = "PFN%sPROC"%f.extfunc.name.upper()
+ else:
+ f.typedef = "PFN%sPROC"%f.name.upper()
+
+if ver:
+ ver = map(int, ver.split('.'))
+
+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 <GL/glext.h>
+#include <msp/gl/extension.h>
+#include <msp/gl/gl.h>
namespace Msp {
namespace GL {
-
""")
+if funcs:
+ out.write("\n")
for f in funcs:
- out.write("extern PFNGL%sPROC gl%s;\n"%(f.upper(), f))
+ 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
#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("\nvoid init_%s()\n{\n"%ext.lower())
-for f in funcs:
- out.write("\tgl%s = reinterpret_cast<PFNGL%sPROC>(get_proc_address(\"gl%s\"));\n"%(f, f.upper(), f))
+ out.write("%s %s = 0;\n"%(f.typedef, f.name))
+
+out.write("\nExtension::SupportLevel init_%s()\n{\n"%ext.lower())
+if ver:
+ out.write("\tif(is_version_at_least(%d, %d)"%tuple(ver))
+ if bp_ext:
+ out.write(" || is_supported(\"GL_%s\")"%bp_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!=bp_ext:
+ out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(ext))
+ for f in funcs:
+ n = f.name
+ if f.extfunc:
+ n = f.extfunc.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("\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