]> git.tdb.fi Git - libs/gl.git/blob - scripts/extgen.py
Migrate to the new XML-based OpenGL API registry
[libs/gl.git] / scripts / extgen.py
1 #!/usr/bin/python
2
3 import sys
4 import os
5 import xml.dom
6 import xml.dom.minidom
7
8 if len(sys.argv)<2:
9         print """Usage:
10   extgen.py <extension> [<version>] [<secondary> ...]"
11
12 Reads gl.spec and generates files to use <extension>.  Any promoted functions
13 are exposed with their promoted names.  If <secondary> extensions are given,
14 any promoted functions from those are pulled in as well.  <version> can be
15 given to override the version where <extension> was promoted to core."""
16         sys.exit(0)
17
18 ext = sys.argv[1]
19 out_base = None
20 if ext.endswith(".glext"):
21         fn = ext
22         ext = None
23         ver = None
24         secondary = []
25         for line in open(fn):
26                 parts = line.split()
27                 if parts[0]=="extension":
28                         ext = parts[1]
29                 elif parts[0]=="core_version":
30                         ver = parts[1]
31                 elif parts[0]=="secondary":
32                         secondary.append(parts[1])
33         if len(sys.argv)>=3:
34                 out_base = os.path.splitext(sys.argv[2])[0]
35 else:
36         secondary = sys.argv[2:]
37         ver = None
38         if secondary and secondary[0][0].isdigit():
39                 ver = secondary.pop(0)
40
41 exttype = ext.split('_')[0]
42 bp_ext = None
43
44 if not out_base:
45         out_base = ext.lower()
46
47 class Function:
48         def __init__(self, name):
49                 self.name = name
50                 self.typedef = None
51                 self.version = None
52                 self.category = None
53                 self.vectorequiv = None
54                 self.aliases = []
55                 self.extfunc = None
56
57 funcs = {}
58 cur_func = None
59
60 def get_nested_elements(elem, path):
61         if '/' in path:
62                 head, tail = path.split('/', 1)
63                 result = []
64                 for e in elem.getElementsByTagName(head):
65                         result += get_nested_elements(e, tail)
66                 return result
67         else:
68                 return elem.getElementsByTagName(path)
69
70 def get_text_contents(node):
71         result = ""
72         for c in node.childNodes:
73                 if c.nodeType==xml.dom.Node.TEXT_NODE or c.nodeType==xml.dom.Node.CDATA_SECTION_NODE:
74                         result += c.data
75                 else:
76                         result += get_text_contents(c)
77         return result
78
79 def parse_file(fn):
80         doc = xml.dom.minidom.parse(fn)
81         root = doc.documentElement
82         commands = get_nested_elements(root, "commands/command")
83         for cmd in commands:
84                 name = get_text_contents(get_nested_elements(cmd, "proto/name")[0])
85                 func = funcs.get(name)
86                 if not func:
87                         func = Function(name)
88                         funcs[name] = func
89
90                 aliases = cmd.getElementsByTagName("alias")
91                 for a in aliases:
92                         func.aliases.append(a.getAttribute("name"))
93
94                 vec = cmd.getElementsByTagName("vecequiv")
95                 if vec:
96                         func.vectorequiv = vec[0].getAttribute("name")
97
98         features = root.getElementsByTagName("feature")
99         for feat in features:
100                 api = feat.getAttribute("api")
101                 if api=="gl":
102                         version = feat.getAttribute("number")
103
104                         commands = get_nested_elements(feat, "require/command")
105                         for c in commands:
106                                 name = c.getAttribute("name")
107                                 func = funcs.get(name)
108                                 if func:
109                                         func.version = version
110
111                         if feat.getAttribute("name")=="MSPGL_REMOVE":
112                                 commands = get_nested_elements(feat, "remove/command")
113                                 for c in commands:
114                                         name = c.getAttribute("name")
115                                         if name in funcs:
116                                                 del funcs[name]
117
118         extensions = get_nested_elements(root, "extensions/extension")
119         for ext in extensions:
120                 ext_name = ext.getAttribute("name")
121                 if ext_name.startswith("GL_"):
122                         ext_name = ext_name[3:]
123                 supported = ext.getAttribute("supported").split('|')
124                 if "gl" in supported:
125                         commands = get_nested_elements(ext, "require/command")
126                         for c in commands:
127                                 name = c.getAttribute("name")
128                                 func = funcs.get(name)
129                                 if func:
130                                         func.category = ext_name
131
132 parse_file("gl.xml")
133 parse_file("gl.fixes.xml")
134
135 for f in funcs.itervalues():
136         if f.category==ext or f.category in secondary:
137                 for a in f.aliases:
138                         aliasfunc = funcs.get(a)
139                         if aliasfunc:
140                                 aliasfunc.extfunc = f
141
142 def is_relevant(f):
143         if f.category==ext and not f.aliases:
144                 return True
145         if f.extfunc:
146                 e = f.extfunc
147                 if e.category==ext or e.category in secondary:
148                         return True
149         return False
150
151 funcs = [f for f in funcs.itervalues() if is_relevant(f)]
152 funcs.sort(key=(lambda f: f.name))
153
154 for f in funcs:
155         if not ver:
156                 ver = f.version
157
158         if f.category and not f.name.endswith(exttype):
159                 bp_ext = f.category
160
161         if f.extfunc:
162                 f.typedef = "PFN%sPROC"%f.extfunc.name.upper()
163         else:
164                 f.typedef = "PFN%sPROC"%f.name.upper()
165
166 if ver:
167         ver = map(int, ver.split('.'))
168
169 out = file(out_base+".h", "w")
170 out.write("#ifndef MSP_GL_%s_\n"%ext.upper())
171 out.write("#define MSP_GL_%s_\n"%ext.upper())
172
173 out.write("""
174 #include <msp/gl/extension.h>
175 #include <msp/gl/gl.h>
176
177 namespace Msp {
178 namespace GL {
179 """)
180
181 if funcs:
182         out.write("\n")
183 for f in funcs:
184         out.write("extern %s %s;\n"%(f.typedef, f.name))
185
186 out.write("\nextern Extension %s;\n"%ext)
187
188 out.write("""
189 } // namespace GL
190 } // namespace Msp
191
192 #endif
193 """)
194
195 out = file(out_base+".cpp", "w")
196 out.write("#include \"%s.h\"\n"%ext.lower())
197
198 out.write("""
199 namespace Msp {
200 namespace GL {
201 """)
202
203 if funcs:
204         out.write("\n")
205 for f in funcs:
206         out.write("%s %s = 0;\n"%(f.typedef, f.name))
207
208 out.write("\nExtension::SupportLevel init_%s()\n{\n"%ext.lower())
209 if ver:
210         out.write("\tif(is_version_at_least(%d, %d)"%tuple(ver))
211         if bp_ext:
212                 out.write(" || is_supported(\"GL_%s\")"%bp_ext)
213         out.write(")\n\t{\n")
214         for f in funcs:
215                 out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, f.name))
216         out.write("\t\treturn Extension::CORE;\n")
217         out.write("\t}\n")
218 if ext!=bp_ext:
219         out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(ext))
220         for f in funcs:
221                 n = f.name
222                 if f.extfunc:
223                         n = f.extfunc.name
224                 out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, n))
225         out.write("\t\treturn Extension::EXTENSION;\n")
226         out.write("\t}\n")
227 out.write("\treturn Extension::UNSUPPORTED;\n")
228 out.write("}\n")
229
230 out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(ext, ext, ext.lower()))
231
232 out.write("""
233 } // namespace GL
234 } // namespace Msp
235 """)