Skip to content

Instantly share code, notes, and snippets.

@rubber-duck
Created May 14, 2013 20:12
Show Gist options
  • Save rubber-duck/5579103 to your computer and use it in GitHub Desktop.
Save rubber-duck/5579103 to your computer and use it in GitHub Desktop.
import xml.etree.ElementTree as ET
import string
core_3_0 = [
"VERSION_1_0",
"VERSION_1_1",
"VERSION_1_2",
"VERSION_1_3",
"VERSION_1_4",
"VERSION_1_5",
"VERSION_2_0",
"VERSION_2_1",
"VERSION_3_0",
"ARB_vertex_array_object",
"ARB_texture_rg",
"ARB_texture_compression_rgtc",
"ARB_map_buffer_range",
"ARB_half_float_vertex",
"ARB_framebuffer_sRGB",
"ARB_framebuffer_object",
"ARB_depth_buffer_float"]
core_3_1 = [
"VERSION_3_1",
"ARB_uniform_buffer_object",
"ARB_copy_buffer"]
core_3_2 = [
"VERSION_3_2",
"ARB_depth_clamp",
"ARB_draw_elements_base_vertex",
"ARB_fragment_coord_conventions",
"ARB_provoking_vertex",
"ARB_seamless_cube_map",
"ARB_sync",
"ARB_texture_multisample",
"ARB_vertex_array_bgra"]
core_3_3 = [
"VERSION_3_3",
"ARB_texture_rgb10_a2ui",
"ARB_texture_swizzle",
"ARB_timer_query",
"ARB_vertex_type_2_10_10_10_rev",
"ARB_blend_func_extended",
"ARB_occlusion_query2",
"ARB_sampler_objects"]
core_4_0 = [
"VERSION_4_0",
"ARB_draw_indirect",
"ARB_gpu_shader5",
"ARB_gpu_shader_fp64",
"ARB_shader_subroutine",
"ARB_tessellation_shader",
"ARB_transform_feedback2",
"ARB_transform_feedback3"]
core_4_1 = [
"VERSION_4_1",
"ARB_ES2_compatibility",
"ARB_get_program_binary",
"ARB_separate_shader_objects",
"ARB_vertex_attrib_64bit",
"ARB_viewport_array"]
core_4_2 = [
"VERSION_4_2",
"ARB_base_instance",
"ARB_shading_language_420pack",
"ARB_transform_feedback_instanced",
"ARB_compressed_texture_pixel_storage",
"ARB_conservative_depth",
"ARB_internalformat_query",
"ARB_map_buffer_alignment",
"ARB_shader_atomic_counters",
"ARB_shader_image_load_store",
"ARB_shading_language_packing",
"ARB_texture_storage"]
core_4_3 = [
"VERSION_4_3",
"KHR_debug",
"ARB_arrays_of_arrays",
"ARB_clear_buffer_object",
"ARB_compute_shader",
"ARB_copy_image",
"ARB_ES3_compatibility",
"ARB_explicit_uniform_location",
"ARB_fragment_layer_viewport",
"ARB_framebuffer_no_attachments",
"ARB_internalformat_query2",
"ARB_invalidate_subdata",
"ARB_multi_draw_indirect",
"ARB_program_interface_query",
"ARB_shader_image_size",
"ARB_shader_storage_buffer_object",
"ARB_stencil_texturing",
"ARB_texture_buffer_range",
"ARB_texture_query_levels",
"ARB_texture_storage_multisample",
"ARB_texture_view",
"ARB_vertex_attrib_binding"]
core_profile = reduce(lambda a, b: a + b, [core_3_0, core_3_1, core_3_2, core_3_3, core_4_0, core_4_1, core_4_2, core_4_3])
dtypemap = {
"GLenum" : "uint",
"GLboolean" : "ubyte",
"GLbitfield" : "uint",
"GLbyte" : "byte",
"GLshort" : "short",
"GLint" : "int",
"GLsizei" : "int",
"GLubyte" : "ubyte",
"GLushort" : "ushort",
"GLuint" : "uint",
"GLfloat" : "float",
"GLclampf" : "float",
"GLdouble" : "double",
"GLclampd" : "double",
"GLvoid" : "void",
"GLchar" : "char",
"GLintptr" : "ptrdiff_t",
"GLsizeiptr" : "ptrdiff_t",
"GLintptrARB" : "ptrdiff_t",
"GLsizeiptrARB" : "ptrdiff_t",
"GLcharARB" : "char",
"GLhandleARB" : "uint",
"GLhalfARB" : "ushort",
"GLhalfNV" : "ushort",
"GLint64EXT" : "long",
"GLuint64EXT" : "ulont",
"GLint64" : "long",
"GLuint64" : "ulong",
"GLsync" : "void*",
"struct _cl_context " : "void",
"struct _cl_event " : "void",
"_GLfuncptr" : "void",
"GLchar* const" : "char*",
"GLvoid* const" : "void*",
"const GLubyte " : "ubyte",
"GLDEBUGPROCAMD" : "DebugProcAmd",
"GLDEBUGPROCARB" : "DebugProcArb",
"GLDEBUGPROC" : "DebugProc",
"GLvdpauSurfaceNV" : "void",
"void" : "void"}
def to_dtype(spec_type):
ptr_type = spec_type[-1] == "*"
if ptr_type:
return dtypemap[spec_type[:-1]] + "*"
else:
return dtypemap[spec_type]
def to_cfunction(name):
"Convert spec function name to c style function name (add gl prefix)"
return "gl" + name
def to_dfunction(name):
"Convert spec function name to d style function name (camelCase, no gl prefix)"
return name[0].lower() + name[1:]
def to_dconst(name):
"Convert spec constant name to d style const name (camelCase)"
return name
class FunctionArgument:
def __init__(self, node):
"Read function argument definition from XML spec param node"
self.name = node.attrib["name"]
self.name = self.name if self.name != "ref" else "refp"
self.kind = node.attrib["kind"]
self.dtype = to_dtype(node.attrib["type"])
self.is_input = node.attrib["input"]
def d_declaration_str(self):
"Return D argument function declaration string for this argument"
arg_const = "const" if self.is_input and self.kind == "array" else ""
arg_ptr = "*" if self.kind == "array" or self.kind == "reference" else ""
return ("%s %s%s %s" % (arg_const, self.dtype, arg_ptr, self.name)).strip()
class Function:
def __init__(self, node):
self.name = node.attrib["name"]
self.dname = to_dfunction(self.name)
self.cname = to_cfunction(self.name)
self.return_dtype = to_dtype(node.attrib["return"])
self.removed = node.get("removed")
self.version = node.get("version")
self.category = node.attrib["category"]
self.profile = node.get("profile")
self.args = []
for arg in node:
assert arg.tag == "param"
self.args.append(FunctionArgument(arg))
def d_declaration_str(self):
"Return D function declaration string"
return "%s function (%s) %s;" % (self.return_dtype, ", ".join([a.d_declaration_str() for a in self.args]), self.dname)
def d_load_str(self):
"Return D statement that loads this function in to global delegate"
return "bindFunc(%s, `%s`);" % (self.dname, self.cname)
class Enum:
def __init__(self, node):
self.name = node.attrib["name"]
self.dname = to_dconst(self.name)
self.ref = node.get("ref")
self.version = node.get("version")
if self.ref == None:
self.value = node.attrib["value"]
self.value = "0xFFFFFFFF" if self.value == "0xFFFFFFFFFFFFFFFF" else self.value
else:
self.value = None
self.removed = node.get("removed")
def d_declaration_str(self, enum_map):
return "%s = %s" % ((self.dname, self.value) if self.ref == None else (self.dname, enum_map[self.ref].value))
class Spec:
def __init__(self, source):
spec = ET.parse(source).getroot()
for td in spec.find("typemap"):
if td.attrib["typename"] == "void" or td.attrib["C-lang"][:3] == "GLU":
continue
dtypemap[td.attrib["typename"]] = to_dtype(td.attrib["C-lang"])
self.enums = dict((e.name, e) for e in [Enum(e) for e in spec.find("enumerations")])
self.functions = [Function(f) for f in spec.find("functions").find("function-defs")]
def write_core_d_module(self, target):
# module header
target.write("module toybox.render.gl.gl;\nimport toybox.platform;\n\n\n")
# write debugging
target.write("/* Debugging callback type */\n")
target.write("alias extern(System) void function(uint source, uint type, uint id, uint severity, int length, const char* message, void* userParam) DebugProc;\n\n\n")
# write enum constants
target.write("/* Core profile constants (removed constants removed in 3.1 and extension constants are in glext) */\n")
target.write("enum : uint\n{\n")
enums_len = len(self.enums)
for enum in self.enums.values():
# only generating 3.1 core profile (ignore ext and removed enums)
if enum.removed == "3.1" or enum.version == None:
continue
target.write("\t")
target.write(enum.d_declaration_str(self.enums))
target.write(",\n")
target.write("\n};\n\n")
# group functions by category
fncategories = {}
for fn in self.functions:
if not fn.category in fncategories:
fncategories[fn.category] = []
# skip compatibility profile and non core extensions
if fn.profile == "compatibility" or fn.version == None or not fn.category in core_profile:
continue
fncategories[fn.category].append(fn)
# write functions
target.write("/* GL functions */\n")
target.write("__gshared \n{\n\textern (C)\n\t{\n");
for cat, fns in fncategories.items():
if len(fns) > 0:
target.write("\t\t/*%s*/\n" % cat)
for fn in fns:
target.write("\t\t")
target.write(fn.d_declaration_str())
target.write("\n")
target.write("\t};\n};\n\n")
# write function loader
target.write("void loadLibrary(int profile)\n{\n\tassert(profile > 30 && profile < 43);\n")
profile_map = [
("30", core_3_0),
("31", core_3_1),
("32", core_3_2),
("33", core_3_3),
("40", core_4_0),
("41", core_4_1),
("42", core_4_2),
("43", core_4_3)
]
for profile, categories in profile_map:
target.write("\tif(profile >= %s)\n\t{\n" % profile)
for category in categories:
if not category in fncategories:
continue
target.write("\t\t/*%s*/\n" % category)
for function in fncategories[category]:
target.write("\t\t")
target.write(function.d_load_str())
target.write("\n")
target.write("\t};\n")
target.write("}")
Spec("opengl.xml").write_core_d_module(file("gl.d", "w"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment