1 ##########################################################################
3 # Copyright 2011 Jose Fonseca
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 ##########################################################################/
27 '''Generate code to dump most GL state into JSON.'''
33 from glparams import *
37 ('GL_TEXTURE_1D', 'GL_TEXTURE_BINDING_1D'),
38 ('GL_TEXTURE_2D', 'GL_TEXTURE_BINDING_2D'),
39 ('GL_TEXTURE_3D', 'GL_TEXTURE_BINDING_3D'),
40 ('GL_TEXTURE_RECTANGLE', 'GL_TEXTURE_BINDING_RECTANGLE'),
41 ('GL_TEXTURE_CUBE_MAP', 'GL_TEXTURE_BINDING_CUBE_MAP')
46 '''Objects that describes how to inflect.'''
54 def __init__(self, radical, inflections, suffix = ''):
55 self.radical = radical
56 self.inflections = inflections
59 def reduced_type(self, type):
60 if type in self.inflections:
62 if type in self.reduced_types:
63 return self.reduced_type(self.reduced_types[type])
64 raise NotImplementedError
66 def inflect(self, type):
67 return self.radical + self.inflection(type) + self.suffix
69 def inflection(self, type):
70 type = self.reduced_type(type)
71 assert type in self.inflections
72 return self.inflections[type]
75 return self.radical + self.suffix
78 class StateGetter(Visitor):
79 '''Type visitor that is able to extract the state via one of the glGet*
82 It will declare any temporary variable
85 def __init__(self, radical, inflections, suffix=''):
86 self.inflector = GetInflector(radical, inflections)
89 def __call__(self, *args):
92 for function, type, count, name in parameters:
97 type = Array(type, str(count))
99 return type, self.visit(type, args)
101 raise NotImplementedError
103 def temp_name(self, args):
104 '''Return the name of a temporary variable to hold the state.'''
107 return pname[3:].lower()
109 def visit_const(self, const, args):
110 return self.visit(const.type, args)
112 def visit_scalar(self, type, args):
113 temp_name = self.temp_name(args)
114 elem_type = self.inflector.reduced_type(type)
115 inflection = self.inflector.inflect(type)
116 if inflection.endswith('v'):
117 print ' %s %s = 0;' % (elem_type, temp_name)
118 print ' %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
120 print ' %s %s = %s(%s);' % (elem_type, temp_name, inflection + self.suffix, ', '.join(args))
123 def visit_string(self, string, args):
124 temp_name = self.temp_name(args)
125 inflection = self.inflector.inflect(string)
126 assert not inflection.endswith('v')
127 print ' %s %s = (%s)%s(%s);' % (string, temp_name, string, inflection + self.suffix, ', '.join(args))
130 def visit_alias(self, alias, args):
131 return self.visit_scalar(alias, args)
133 def visit_enum(self, enum, args):
134 return self.visit(GLint, args)
136 def visit_bitmask(self, bitmask, args):
137 return self.visit(GLint, args)
139 def visit_array(self, array, args):
140 temp_name = self.temp_name(args)
141 if array.length == '1':
142 return self.visit(array.type)
143 elem_type = self.inflector.reduced_type(array.type)
144 inflection = self.inflector.inflect(array.type)
145 assert inflection.endswith('v')
146 print ' %s %s[%s];' % (elem_type, temp_name, array.length)
147 print ' memset(%s, 0, %s * sizeof *%s);' % (temp_name, array.length, temp_name)
148 print ' %s(%s, %s);' % (inflection + self.suffix, ', '.join(args), temp_name)
151 def visit_opaque(self, pointer, args):
152 temp_name = self.temp_name(args)
153 inflection = self.inflector.inflect(pointer)
154 assert inflection.endswith('v')
155 print ' GLvoid *%s;' % temp_name
156 print ' %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
160 glGet = StateGetter('glGet', {
169 glGetMaterial = StateGetter('glGetMaterial', {I: 'iv', F: 'fv'})
170 glGetLight = StateGetter('glGetLight', {I: 'iv', F: 'fv'})
171 glGetVertexAttrib = StateGetter('glGetVertexAttrib', {I: 'iv', F: 'fv', D: 'dv', P: 'Pointerv'})
172 glGetTexParameter = StateGetter('glGetTexParameter', {I: 'iv', F: 'fv'})
173 glGetTexEnv = StateGetter('glGetTexEnv', {I: 'iv', F: 'fv'})
174 glGetTexLevelParameter = StateGetter('glGetTexLevelParameter', {I: 'iv', F: 'fv'})
175 glGetShader = StateGetter('glGetShaderiv', {I: 'iv'})
176 glGetProgram = StateGetter('glGetProgram', {I: 'iv'})
177 glGetProgramARB = StateGetter('glGetProgram', {I: 'iv', F: 'fv', S: 'Stringv'}, 'ARB')
180 class JsonWriter(Visitor):
181 '''Type visitor that will dump a value of the specified type through the
184 It expects a previously declared JSONWriter instance named "json".'''
186 def visit_literal(self, literal, instance):
187 if literal.format == 'Bool':
188 print ' json.writeBool(%s);' % instance
189 elif literal.format in ('SInt', 'Uint', 'Float', 'Double'):
190 print ' json.writeNumber(%s);' % instance
192 raise NotImplementedError
194 def visit_string(self, string, instance):
195 assert string.length is None
196 print ' json.writeString((const char *)%s);' % instance
198 def visit_enum(self, enum, instance):
199 if enum.expr == 'GLenum':
200 print ' dumpEnum(json, %s);' % instance
202 print ' json.writeNumber(%s);' % instance
204 def visit_bitmask(self, bitmask, instance):
205 raise NotImplementedError
207 def visit_alias(self, alias, instance):
208 self.visit(alias.type, instance)
210 def visit_opaque(self, opaque, instance):
211 print ' json.writeNumber((size_t)%s);' % instance
215 def visit_array(self, array, instance):
216 index = '__i%u' % JsonWriter.__index
217 JsonWriter.__index += 1
218 print ' json.beginArray();'
219 print ' for (unsigned %s = 0; %s < %s; ++%s) {' % (index, index, array.length, index)
220 self.visit(array.type, '%s[%s]' % (instance, index))
222 print ' json.endArray();'
227 '''Class to generate code to dump all GL state in JSON format via
234 print '#include <string.h>'
236 print '#include "json.hpp"'
237 print '#include "glproc.hpp"'
238 print '#include "glsize.hpp"'
239 print '#include "glstate.hpp"'
241 print 'namespace glstate {'
245 print 'enumToString(GLenum pname)'
247 print ' switch(pname) {'
248 for name in GLenum.values:
249 print ' case %s:' % name
250 print ' return "%s";' % name
252 print ' return NULL;'
258 print 'dumpEnum(JSONWriter &json, GLenum pname)'
260 print ' const char *s = enumToString(pname);'
262 print ' json.writeString(s);'
264 print ' json.writeNumber(pname);'
269 print 'void dumpParameters(JSONWriter &json)'
271 print ' json.beginMember("parameters");'
272 print ' json.beginObject();'
274 self.dump_atoms(glGet)
276 self.dump_material_params()
277 self.dump_light_params()
278 self.dump_vertex_attribs()
279 self.dump_texenv_params()
280 self.dump_program_params()
281 self.dump_texture_parameters()
283 print ' json.endObject();'
284 print ' json.endMember(); // parameters'
288 print '} /*namespace glstate */'
290 def dump_material_params(self):
291 for face in ['GL_FRONT', 'GL_BACK']:
292 print ' json.beginMember("%s");' % face
293 print ' json.beginObject();'
294 self.dump_atoms(glGetMaterial, face)
295 print ' json.endObject();'
298 def dump_light_params(self):
299 print ' GLint max_lights = 0;'
300 print ' __glGetIntegerv(GL_MAX_LIGHTS, &max_lights);'
301 print ' for (GLint index = 0; index < max_lights; ++index) {'
302 print ' GLenum light = GL_LIGHT0 + index;'
303 print ' if (glIsEnabled(light)) {'
304 print ' char name[32];'
305 print ' snprintf(name, sizeof name, "GL_LIGHT%i", index);'
306 print ' json.beginMember(name);'
307 print ' json.beginObject();'
308 self.dump_atoms(glGetLight, ' GL_LIGHT0 + index')
309 print ' json.endObject();'
310 print ' json.endMember(); // GL_LIGHTi'
315 def dump_texenv_params(self):
316 for target in ['GL_TEXTURE_ENV', 'GL_TEXTURE_FILTER_CONTROL', 'GL_POINT_SPRITE']:
317 if target != 'GL_TEXTURE_FILTER_CONTROL':
318 print ' if (glIsEnabled(%s)) {' % target
321 print ' json.beginMember("%s");' % target
322 print ' json.beginObject();'
323 self.dump_atoms(glGetTexEnv, target)
324 print ' json.endObject();'
327 def dump_vertex_attribs(self):
328 print ' GLint max_vertex_attribs = 0;'
329 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
330 print ' for (GLint index = 0; index < max_vertex_attribs; ++index) {'
331 print ' char name[32];'
332 print ' snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
333 print ' json.beginMember(name);'
334 print ' json.beginObject();'
335 self.dump_atoms(glGetVertexAttrib, 'index')
336 print ' json.endObject();'
337 print ' json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
342 'GL_FRAGMENT_PROGRAM_ARB',
343 'GL_VERTEX_PROGRAM_ARB',
346 def dump_program_params(self):
347 for target in self.program_targets:
348 print ' if (glIsEnabled(%s)) {' % target
349 print ' json.beginMember("%s");' % target
350 print ' json.beginObject();'
351 self.dump_atoms(glGetProgramARB, target)
352 print ' json.endObject();'
355 def dump_texture_parameters(self):
357 print ' GLint active_texture = GL_TEXTURE0;'
358 print ' glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
359 print ' GLint max_texture_coords = 0;'
360 print ' glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
361 print ' GLint max_combined_texture_image_units = 0;'
362 print ' glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
363 print ' GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
364 print ' for (GLint unit = 0; unit < max_units; ++unit) {'
365 print ' char name[32];'
366 print ' snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
367 print ' json.beginMember(name);'
368 print ' glActiveTexture(GL_TEXTURE0 + unit);'
369 print ' json.beginObject();'
370 print ' GLint texture;'
372 for target, binding in texture_targets:
373 print ' // %s' % target
374 print ' texture = 0;'
375 print ' glGetIntegerv(%s, &texture);' % binding
376 print ' if (glIsEnabled(%s) || texture) {' % target
377 print ' json.beginMember("%s");' % target
378 print ' json.beginObject();'
379 self.dump_atoms(glGetTexParameter, target)
380 # We only dump the first level parameters
381 self.dump_atoms(glGetTexLevelParameter, target, "0")
382 print ' json.endObject();'
383 print ' json.endMember(); // %s' % target
386 print ' json.endObject();'
387 print ' json.endMember(); // GL_TEXTUREi'
389 print ' glActiveTexture(active_texture);'
393 def dump_atoms(self, getter, *args):
394 for function, type, count, name in parameters:
395 inflection = getter.inflector.radical + getter.suffix
396 if inflection not in function.split(','):
400 print ' // %s' % name
402 type, value = getter(*(args + (name,)))
403 print ' if (glGetError() != GL_NO_ERROR) {'
404 #print ' std::cerr << "warning: %s(%s) failed\\n";' % (inflection, name)
406 print ' json.beginMember("%s");' % name
407 JsonWriter().visit(type, value)
408 print ' json.endMember();'
414 if __name__ == '__main__':