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."""
28 if ext.endswith(".glext"):
35 if parts[0]=="extension":
37 elif parts[0]=="core_version":
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 ver = secondary.pop(0)
49 exttype = ext.split('_')[0]
53 out_base = ext.lower()
55 ### XML file parsing ###
61 def __init__(self, name, kind):
69 class Function(Thing):
70 def __init__(self, name):
71 Thing.__init__(self, name, Thing.FUNCTION)
72 self.return_type = "void"
75 self.vectorequiv = None
78 def __init__(self, name):
79 Thing.__init__(self, name, Thing.ENUM)
84 def get_nested_elements(elem, path):
86 head, tail = path.split('/', 1)
88 for e in elem.getElementsByTagName(head):
89 result += get_nested_elements(e, tail)
92 return elem.getElementsByTagName(path)
94 def get_text_contents(node):
96 for c in node.childNodes:
97 if c.nodeType==xml.dom.Node.TEXT_NODE or c.nodeType==xml.dom.Node.CDATA_SECTION_NODE:
100 result += get_text_contents(c)
104 doc = xml.dom.minidom.parse(fn)
105 root = doc.documentElement
106 commands = get_nested_elements(root, "commands/command")
108 proto = cmd.getElementsByTagName("proto")[0]
109 name = get_text_contents(proto.getElementsByTagName("name")[0])
110 func = things.get(name)
112 func = Function(name)
115 aliases = cmd.getElementsByTagName("alias")
117 func.aliases.append(a.getAttribute("name"))
119 vec = cmd.getElementsByTagName("vecequiv")
121 func.vectorequiv = vec[0].getAttribute("name")
123 ptype = proto.getElementsByTagName("ptype")
125 func.return_type = get_text_contents(ptype[0])
127 for c in proto.childNodes:
128 if c.nodeType==xml.dom.Node.TEXT_NODE and c.data.strip():
129 func.return_type = c.data.strip()
132 params = cmd.getElementsByTagName("param")
134 func.params.append(get_text_contents(p))
136 enums = get_nested_elements(root, "enums/enum")
138 name = en.getAttribute("name")
139 enum = things.get(name)
144 enum.value = int(en.getAttribute("value"), 16)
146 features = root.getElementsByTagName("feature")
147 for feat in features:
148 api = feat.getAttribute("api")
150 version = feat.getAttribute("number")
152 commands = get_nested_elements(feat, "require/command")
153 enums = get_nested_elements(feat, "require/enum")
154 for t in itertools.chain(commands, enums):
155 name = t.getAttribute("name")
156 thing = things.get(name)
158 thing.version = version
160 if feat.getAttribute("name")=="MSPGL_REMOVE":
161 commands = get_nested_elements(feat, "remove/command")
162 enums = get_nested_elements(feat, "require/enum")
163 for t in itertools.chain(commands, enums):
164 name = t.getAttribute("name")
168 extensions = get_nested_elements(root, "extensions/extension")
169 for ext in extensions:
170 ext_name = ext.getAttribute("name")
171 if ext_name.startswith("GL_"):
172 ext_name = ext_name[3:]
173 supported = ext.getAttribute("supported").split('|')
174 if "gl" in supported:
175 commands = get_nested_elements(ext, "require/command")
176 enums = get_nested_elements(ext, "require/enum")
177 for t in itertools.chain(commands, enums):
178 name = t.getAttribute("name")
179 thing = things.get(name)
181 thing.extension = ext_name
184 parse_file("gl.fixes.xml")
186 ### Additional processing ###
188 # Find aliases for enums
189 enums = [t for t in things.itervalues() if t.kind==Thing.ENUM]
190 core_enums_by_value = dict((e.value, e) for e in enums if e.version)
193 if e.kind==t.ENUM and e.extension:
194 ce = core_enums_by_value.get(e.value)
196 e.aliases.append(ce.name)
198 # Create references from core things to their extension counterparts
199 for t in things.itervalues():
200 if t.extension==ext or t.extension in secondary:
202 alias = things.get(a)
207 # Unpromoted extension things are relevant
208 if t.extension==ext and not t.aliases:
211 # Core things promoted from the extension are also relevant
214 if e.extension==ext or e.extension in secondary:
219 funcs = [t for t in things.itervalues() if t.kind==Thing.FUNCTION and is_relevant(t)]
220 funcs.sort(key=(lambda f: f.name))
221 enums = [e for e in enums if is_relevant(e)]
222 enums.sort(key=(lambda e: e.value))
224 for t in itertools.chain(funcs, enums):
228 # Things in backport extensions don't acquire an extension suffix
229 if t.extension and not t.name.endswith(exttype):
230 backport_ext = t.extension
234 # Typedefs for early core functions are not available in all
236 f.typedef = "PFN%sPROC"%f.source.name.upper()
238 f.typedef = "PFN%sPROC"%f.name.upper()
241 ver = map(int, ver.split('.'))
245 out = file(out_base+".h", "w")
246 out.write("#ifndef MSP_GL_%s_\n"%ext.upper())
247 out.write("#define MSP_GL_%s_\n"%ext.upper())
250 #include <msp/gl/extension.h>
251 #include <msp/gl/gl.h>
260 out.write("#if defined(__APPLE__) || !defined(GL_%s)\n"%ext)
262 out.write("typedef %s (*%s)(%s);\n"%(f.return_type, f.typedef, ", ".join(f.params)))
263 out.write("#endif\n\n")
267 out.write("#ifndef GL_VERSION_%s\n"%"_".join(map(str, ver)))
269 out.write("#ifndef GL_%s\n"%ext)
271 out.write("#define %s 0x%04X\n"%(e.name, e.value))
272 out.write("#endif\n\n")
275 out.write("extern %s %s;\n"%(f.typedef, f.name))
277 out.write("extern Extension %s;\n"%ext)
286 out = file(out_base+".cpp", "w")
287 out.write("#include \"%s.h\"\n"%ext.lower())
291 #define GET_PROC_ADDRESS(x) ::x
293 #define GET_PROC_ADDRESS(x) get_proc_address(#x)
302 out.write("%s %s = 0;\n"%(f.typedef, f.name))
304 out.write("\nExtension::SupportLevel init_%s()\n{\n"%ext.lower())
305 out.write("#ifdef GL_%s\n"%ext)
307 out.write("\tif(is_version_at_least(%d, %d)"%tuple(ver))
309 out.write(" || is_supported(\"GL_%s\")"%backport_ext)
310 out.write(")\n\t{\n")
313 out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, f.name))
314 out.write("\t\treturn Extension::CORE;\n")
316 if ext!=backport_ext:
317 out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(ext))
323 out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, n))
324 out.write("\t\treturn Extension::EXTENSION;\n")
326 out.write("#endif\n")
327 out.write("\treturn Extension::UNSUPPORTED;\n")
330 out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(ext, ext, ext.lower()))