9 ### Command line processing ###
13 extgen.py <extension> [<core_version>] [<secondary> ...]
14 extgen.py <extfile> [<outfile>]
16 Reads gl.xml and generates files to use <extension>. Any promoted functions
17 are exposed with their promoted names. If <secondary> extensions are given,
18 any promoted functions from those are pulled in as well. <core_version> can
19 be given to override the version where <extension> was promoted to core.
21 In the second form, the parameters are read from <extfile>. If <outfile> is
22 absent, the extension's lowercased name is used. Anything after the last dot
23 in <outfile> is removed and replaced with cpp and h."""
26 target_ext = sys.argv[1]
28 if target_ext.endswith(".glext"):
35 if parts[0]=="extension":
37 elif parts[0]=="core_version":
38 core_version = parts[1]
39 elif parts[0]=="secondary":
40 secondary.append(parts[1])
42 out_base = os.path.splitext(sys.argv[2])[0]
44 secondary = sys.argv[2:]
46 if secondary and secondary[0][0].isdigit():
47 core_version = secondary.pop(0)
49 ext_type = target_ext.split('_')[0]
53 core_version = map(int, core_version.split('.'))
56 out_base = target_ext.lower()
58 ### XML file parsing ###
64 def __init__(self, name, kind):
72 class Function(Thing):
73 def __init__(self, name):
74 Thing.__init__(self, name, Thing.FUNCTION)
75 self.return_type = "void"
80 def __init__(self, name):
81 Thing.__init__(self, name, Thing.ENUM)
86 def get_nested_elements(elem, path):
87 childElements = [c for c in elem.childNodes if c.nodeType==xml.dom.Node.ELEMENT_NODE]
89 head, tail = path.split('/', 1)
91 for c in childElements:
93 result += get_nested_elements(c, tail)
96 return [c for c in childElements if c.tagName==path]
98 def get_first_child(elem, tag):
99 for c in elem.childNodes:
100 if c.nodeType==xml.dom.Node.ELEMENT_NODE and c.tagName==tag:
104 def get_text_contents(node):
106 for c in node.childNodes:
107 if c.nodeType==xml.dom.Node.TEXT_NODE or c.nodeType==xml.dom.Node.CDATA_SECTION_NODE:
110 result += get_text_contents(c)
113 def parse_command(cmd):
114 proto = get_first_child(cmd, "proto")
115 name = get_text_contents(get_first_child(proto, "name"))
116 func = things.get(name)
118 func = Function(name)
121 aliases = get_nested_elements(cmd, "alias")
122 func.aliases = [a.getAttribute("name") for a in aliases]
124 ptype = get_first_child(proto, "ptype")
126 func.return_type = get_text_contents(ptype)
128 for c in proto.childNodes:
129 if c.nodeType==xml.dom.Node.TEXT_NODE and c.data.strip():
130 func.return_type = c.data.strip()
133 params = get_nested_elements(cmd, "param")
134 func.params = map(get_text_contents, params)
137 name = en.getAttribute("name")
138 enum = things.get(name)
143 enum.value = int(en.getAttribute("value"), 16)
145 def parse_feature(feat):
146 api = feat.getAttribute("api")
148 version = feat.getAttribute("number")
150 version = map(int, version.split('.'))
154 commands = get_nested_elements(feat, "require/command")
155 enums = get_nested_elements(feat, "require/enum")
156 for t in itertools.chain(commands, enums):
157 name = t.getAttribute("name")
158 thing = things.get(name)
160 thing.version = version
162 if feat.getAttribute("name")=="MSPGL_REMOVE":
163 commands = get_nested_elements(feat, "remove/command")
164 enums = get_nested_elements(feat, "remove/enum")
165 for t in itertools.chain(commands, enums):
166 name = t.getAttribute("name")
170 def parse_extension(ext):
171 ext_name = ext.getAttribute("name")
172 if ext_name.startswith("GL_"):
173 ext_name = ext_name[3:]
175 supported = ext.getAttribute("supported").split('|')
176 if "gl" in supported:
177 commands = get_nested_elements(ext, "require/command")
178 enums = get_nested_elements(ext, "require/enum")
179 for t in itertools.chain(commands, enums):
180 name = t.getAttribute("name")
181 thing = things.get(name)
183 thing.extension = ext_name
186 doc = xml.dom.minidom.parse(fn)
187 root = doc.documentElement
189 commands = get_nested_elements(root, "commands/command")
193 enums = get_nested_elements(root, "enums/enum")
197 features = get_nested_elements(root, "feature")
198 for feat in features:
201 extensions = get_nested_elements(root, "extensions/extension")
202 for ext in extensions:
206 parse_file("gl.fixes.xml")
208 ### Additional processing ###
210 # Find aliases for enums
211 enums = [t for t in things.itervalues() if t.kind==Thing.ENUM]
212 core_enums_by_value = dict((e.value, e) for e in enums if e.version)
215 if e.kind==t.ENUM and e.extension:
216 ce = core_enums_by_value.get(e.value)
218 e.aliases.append(ce.name)
220 # Create references from core things to their extension counterparts
221 for t in things.itervalues():
222 if t.extension==target_ext or t.extension in secondary:
224 alias = things.get(a)
229 # Unpromoted extension things are relevant
230 if t.extension==target_ext and not t.aliases:
233 # Core things promoted from the extension are also relevant
236 if e.extension==target_ext or e.extension in secondary:
241 funcs = [t for t in things.itervalues() if t.kind==Thing.FUNCTION and is_relevant(t)]
242 funcs.sort(key=(lambda f: f.name))
243 enums = filter(is_relevant, enums)
244 enums.sort(key=(lambda e: e.value))
246 for t in itertools.chain(funcs, enums):
248 core_version = t.version
250 # Things in backport extensions don't acquire an extension suffix
251 if t.extension and not t.name.endswith(ext_type):
252 backport_ext = t.extension
256 # Typedefs for early core functions are not available in all
258 f.typedef = "PFN%sPROC"%f.source.name.upper()
260 f.typedef = "PFN%sPROC"%f.name.upper()
264 out = file(out_base+".h", "w")
265 out.write("#ifndef MSP_GL_%s_\n"%target_ext.upper())
266 out.write("#define MSP_GL_%s_\n"%target_ext.upper())
269 #include <msp/gl/extension.h>
270 #include <msp/gl/gl.h>
279 out.write("#if defined(__APPLE__) || !defined(GL_%s)\n"%target_ext)
281 out.write("typedef %s (*%s)(%s);\n"%(f.return_type, f.typedef, ", ".join(f.params)))
282 out.write("#endif\n\n")
286 out.write("#ifndef GL_VERSION_%s\n"%"_".join(map(str, core_version)))
288 out.write("#ifndef GL_%s\n"%target_ext)
290 out.write("#define %s 0x%04X\n"%(e.name, e.value))
291 out.write("#endif\n\n")
294 out.write("extern %s %s;\n"%(f.typedef, f.name))
296 out.write("extern Extension %s;\n"%target_ext)
305 out = file(out_base+".cpp", "w")
306 out.write("#include \"%s.h\"\n"%target_ext.lower())
311 #define GET_PROC_ADDRESS(x) ::x
313 #define GET_PROC_ADDRESS(x) get_proc_address(#x)
323 out.write("%s %s = 0;\n"%(f.typedef, f.name))
325 out.write("\nExtension::SupportLevel init_%s()\n{\n"%target_ext.lower())
326 out.write("#ifdef GL_%s\n"%target_ext)
328 out.write("\tif(is_version_at_least(%d, %d)"%tuple(core_version))
330 out.write(" || is_supported(\"GL_%s\")"%backport_ext)
331 out.write(")\n\t{\n")
334 out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, f.name))
335 out.write("\t\treturn Extension::CORE;\n")
337 if target_ext!=backport_ext:
338 out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(target_ext))
344 out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, n))
345 out.write("\t\treturn Extension::EXTENSION;\n")
347 out.write("#endif\n")
348 out.write("\treturn Extension::UNSUPPORTED;\n")
351 out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(target_ext, target_ext, target_ext.lower()))