3 Commits 3aefcdf39e ... ad2603897f

Author SHA1 Message Date
  Niels Nesse ad2603897f Remove per extension type tracking code 9 years ago
  Niels Nesse 97930b0f83 Add support for GLES2 9 years ago
  Niels Nesse c3a0b65e7f Don't duplicate "builtin" types when printing top level types 9 years ago
2 changed files with 55 additions and 72 deletions
  1. 12 7
      Readme.md
  2. 43 65
      glbindify.cpp

+ 12 - 7
Readme.md

@@ -1,14 +1,14 @@
 glbindify
 =========
 
-glbindify is a command line tool that generates C bindings for OpenGL, WGL, EGL, and GLX.  The generated bindings can then be included in your projects, eliminating the need to link to a seperate loader library. The bindings are generated using XML API specifications mainained by khronos so only these XML files need to be updated to support new GL versions or extensions.
+glbindify is a command line tool that generates C bindings for OpenGL, GLES2 (and higher), WGL, EGL, and GLX.  The generated bindings can then be included in your projects, eliminating the need to link to a seperate loader library. The bindings are generated using XML API specifications mainained by khronos so only these XML files need to be updated to support new GL versions or extensions.
 
 It supports generating bindings for core profile contexts only which substantially reduces the size of the bindings. The generated header file only exposes functions and enums for API versions and extensions you select at compile time, ensuring that your application does not accidentally aquire unwanted dependencies.
 
 Command line usage
 ------------------
 
-To generate bindings just specify the API name to `glbindify` where the API name is one of `gl`, `wgl`, 'egl', or `glx`. The tool will generate a source file and header file for the API in the current directory with the names `glb-<api>.c` and `glb-<api>.h`.
+To generate bindings just specify the API name to `glbindify` where the API name is one of `gl`, `gles2`, `wgl`, 'egl', or `glx`. The tool will generate a source file and header file for the API in the current directory with the names `glb-<api>.c` and `glb-<api>.h`.
 
 Example: Generate C bindings for OpenGL core profile contexts
 
@@ -55,6 +55,16 @@ Example: Checking for the `GL_ARB_texture_storage` extension
 		...
 	}
 
+Using with EGL
+--------------
+
+By default OpenGL bindings will try to locate GL functions using `glXGetProcAddress()`. If you want to use EGL you should define `GLB_USE_EGL` when you compile your GL bindings. This will cause `eglGetProcAddress()` to be called. The EGL API itself will use `eglGetProcAddress()` without this definition.
+
+GLES
+----
+
+Only GLES 2.0 and higher is supported. GLES3 is not a considered separate API and is supported when `gles2` is specified as the API.
+
 Binding namespace
 -----------------
 
@@ -74,11 +84,6 @@ Example: Using bindings with a `myapp` namespace
 	...
 	glDrawArrays(...);
 
-Using with EGL
---------------
-
-By default OpenGL bindings will try to locate GL functions using `glXGetProcAddress()`. If you want to use EGL you should define GLB_USE_EGL when you compile your GL bindings. This will cause `eglGetProcAddress()` to be called. The EGL API itself will use `eglGetProcAddress()` without this definition.
-
 Building
 --------
 

+ 43 - 65
glbindify.cpp

@@ -38,6 +38,7 @@
 
 enum API {
 	API_GL,
+	API_GLES2,
 	API_EGL,
 	API_GLX,
 	API_WGL
@@ -167,14 +168,12 @@ struct command {
 
 typedef std::map<const char *, command *, cstring_compare> commands_type;
 typedef std::set<const char *, cstring_compare> enums_type;
-typedef std::map<const char *, std::string, cstring_compare> types_type;
 
 struct interface {
 	enums_type enums;
 	commands_type commands;
 	enums_type removed_enums;
 	commands_type removed_commands;
-	types_type types;
 };
 
 //Api description
@@ -195,10 +194,8 @@ std::vector<enumeration *> g_enumerations;
 typedef std::map<const char *, command *, cstring_compare> commands_type;
 commands_type g_commands;
 
-typedef std::map<const char *, std::string, cstring_compare> types_type;
+typedef std::vector<std::string> types_type;
 types_type g_types;
-typedef std::vector<std::string> top_types_type;
-top_types_type g_top_types;
 
 typedef std::map<int, interface *> feature_interfaces_type;
 feature_interfaces_type g_feature_interfaces;
@@ -385,9 +382,9 @@ class interface_visitor : public XMLVisitor
 		if (&elem == &m_root) {
 			return true;
 		} else if (tag_test(elem, "require") && elem.Parent() == &m_root) {
-			return !elem.Attribute("profile") || !strcmp(elem.Attribute("profile"), "core");
+			return g_api != API_GL || !elem.Attribute("profile") || !strcmp(elem.Attribute("profile"), "core");
 		} else if (tag_test(elem, "remove") && elem.Parent() == &m_root) {
-			return !elem.Attribute("profile") || !strcmp(elem.Attribute("profile"), "core");
+			return g_api != API_GL || !elem.Attribute("profile") || !strcmp(elem.Attribute("profile"), "core");
 		} else if (tag_stack_test(elem, "enum", "require")) {
 			const char *enumeration_name = elem.Attribute("name");
 			if (is_enum_in_namespace(&enumeration_name)) {
@@ -458,11 +455,11 @@ class type_visitor :  public XMLVisitor
 	bool VisitExit(const XMLElement &elem)
 	{
 		if (m_type_name != NULL) {
-			if (tag_stack_test(elem, "type", "types", "registry")) {
-				g_common_gl_typedefs.insert(m_type_name);
-				g_top_types.push_back(m_type_decl);
-			} else if (tag_test(elem, "type")) {
-				g_types[m_type_name] = m_type_decl;
+			if (tag_test(elem, "type")) {
+				if (!g_common_gl_typedefs.count(m_type_name)) {
+					g_common_gl_typedefs.insert(m_type_name);
+					g_types.push_back(m_type_decl);
+				}
 			}
 		}
 		return true;
@@ -507,7 +504,7 @@ class khronos_registry_visitor : public XMLVisitor
 			const char *supported = elem.Attribute("supported");
 			char *supported_copy = strdup(supported);
 			char *token = strtok(supported_copy, "|");
-			const char *name = elem.Attribute("name") + strlen(g_api_name) + 1;
+			const char *name = elem.Attribute("name") + strlen(g_enumeration_prefix);
 
 			//We can't support many SGI extensions due to missing types
 			if (g_api == API_GLX && (strstr(name, "SGI") == name) && !strstr(name,"swap_control")) {
@@ -558,20 +555,6 @@ void print_interface_declaration(struct interface *iface, FILE *header_file)
 {
 	const char *enumeration_prefix = g_enumeration_prefix;
 
-	FOREACH(val, iface->types, types_type) {
-		char *temp = strdup(val->first);
-		char *cur;
-		for (cur = temp; *cur; cur++)
-			if (*cur == ' ')
-				*cur = '_';
-		indent_fprintf(header_file, "#ifndef %s_TYPE_%s\n", g_macro_prefix, temp);
-		indent_fprintf(header_file, "#define %s_TYPE_%s\n", g_macro_prefix, temp);
-		indent_fprintf(header_file, "%s\n", val->second.c_str());
-		indent_fprintf(header_file, "#endif\n", enumeration_prefix, val->first);
-		free(temp);
-	}
-
-	indent_fprintf(header_file, "\n");
 	FOREACH (val, iface->removed_enums, enums_type)
 		fprintf(header_file, "#undef %s%s\n", enumeration_prefix, *val);
 
@@ -588,7 +571,8 @@ void print_interface_declaration(struct interface *iface, FILE *header_file)
 		}
 	}
 
-	indent_fprintf(header_file, "\n");
+	if (iface->enums.size())
+		indent_fprintf(header_file, "\n");
 	FOREACH (iter, iface->removed_commands, commands_type) {
 		command *command = iter->second;
 		fprintf(header_file, "#undef %s%s\n",
@@ -610,22 +594,6 @@ void print_interface_definition(struct interface *iface, FILE *source_file)
 		iter->second->print_initialize(source_file, g_command_prefix);
 }
 
-void interface_include_type(struct interface *iface, const char *type)
-{
-	if (type != NULL && !g_common_gl_typedefs.count(type) && !iface->types.count(type))
-		iface->types[type] = g_types[type];
-}
-
-void interface_resolve_types(struct interface *iface)
-{
-	FOREACH (iter, iface->commands, commands_type) {
-		command *command = iter->second;
-		interface_include_type(iface, command->type);
-		for (std::vector<command::param>::iterator iter = command->params.begin(); iter != command->params.end(); iter++)
-			interface_include_type(iface, iter->type);
-	}
-}
-
 void interface_append(struct interface *iface, const interface &other)
 {
 	iface->enums.insert(other.enums.begin(), other.enums.end());
@@ -664,18 +632,14 @@ void bindify(const char *header_name, int min_version, FILE *header_file , FILE
 
 	bool is_gl_api = g_api == API_GL;
 	FOREACH (iter, g_feature_interfaces, feature_interfaces_type) {
-		if (iter->first > min_version)
-			interface_resolve_types(iter->second);
-		else
+		if (iter->first <= min_version)
 			interface_append(&base_interface, *(iter->second));
 		max_version = iter->first > max_version ? iter->first : max_version;
 		interface_append(&full_interface,*(iter->second));
 	}
 	FOREACH (iter, g_extension_interfaces, extension_interfaces_type) {
-		interface_resolve_types(iter->second);
 		interface_append(&full_interface, *(iter->second));
 	}
-	interface_resolve_types(&base_interface);
 
 	fprintf(header_file, "#ifndef GL_BINDIFY_%s_H\n", g_api_name);
 	fprintf(header_file, "#define GL_BINDIFY_%s_H\n", g_api_name);
@@ -728,7 +692,7 @@ void bindify(const char *header_name, int min_version, FILE *header_file , FILE
 		indent_fprintf(header_file, "#include <khrplatform.h>\n");
 	}
 
-	FOREACH(val, g_top_types, top_types_type)
+	FOREACH(val, g_types, types_type)
 		indent_fprintf(header_file, "%s\n", val->c_str());
 
 	print_interface_declaration(&base_interface, header_file);
@@ -741,7 +705,6 @@ void bindify(const char *header_name, int min_version, FILE *header_file , FILE
 					g_macro_prefix,
 					g_enumeration_prefix,
 					iter->first);
-			indent_fprintf(header_file, "\n");
 			print_interface_declaration(iter->second, header_file);
 			indent_fprintf(header_file, "#endif\n");
 		}
@@ -935,12 +898,12 @@ static void print_help(const char *program_name)
 	printf("Usage: %s [OPTION]...\n", program_name);
 	printf("\n"
 	       "Options:\n"
-	       "  -a,--api <api>                     Generate bindings for API <api>. Must be one\n"
-	       "                                     of 'gl', 'wgl', 'egl', or 'glx'. Default is 'gl'\n"
-	       "  -n,--namespace <Namespace>         Namespace for generated bindings. This is the first\n"
-	       "                                     part of the name of every function and macro.\n"
-	       "  -s,--srcdir <dir>                  Directory to find XML sources\n"
-	       "  -v,--version                       Print version information\n");
+	       "  -a,--api <api>                Generate bindings for API <api>. Must be one\n"
+	       "                                of 'gl', 'wgl', 'egl', 'gles2', or 'glx'. Default is 'gl'\n"
+	       "  -n,--namespace <Namespace>    Namespace for generated bindings. This is the first\n"
+	       "                                part of the name of every function and macro.\n"
+	       "  -s,--srcdir <dir>             Directory to find XML sources\n"
+	       "  -v,--version                  Print version information\n");
 }
 
 int main(int argc, char **argv)
@@ -972,7 +935,6 @@ int main(int argc, char **argv)
 	};
 
 	g_api_name = "gl";
-	g_variant_name = "glcore";
 	const char *srcdir = NULL;
 
 	const char *prefix = "glb";
@@ -996,11 +958,6 @@ int main(int argc, char **argv)
 			break;
 		case 'a':
 			g_api_name = optarg;
-			if (!strcmp(g_api_name, "gl")) {
-				g_variant_name = "glcore";
-			} else {
-				g_variant_name = g_api_name;
-			}
 			break;
 		case 's':
 			srcdir = optarg;
@@ -1025,28 +982,46 @@ int main(int argc, char **argv)
 
 	printf("Generating bindings for %s with namespace '%s'\n", g_api_name, g_prefix);
 
+	const char *xml_name = NULL;
+
 	if (!strcmp(g_api_name, "wgl")) {
 		g_api = API_WGL;
 		g_command_prefix = "wgl";
 		g_enumeration_prefix = "WGL_";
 		g_api_print_name = "WGL";
+		g_variant_name = g_api_name;
+		xml_name = "wgl.xml";
 	} else if (!strcmp(g_api_name, "glx")) {
 		g_api = API_GLX;
 		g_command_prefix = "glX";
 		g_enumeration_prefix = "GLX_";
+		g_variant_name = g_api_name;
+		xml_name = "glx.xml";
 		g_api_print_name = "glX";
 	} else if (!strcmp(g_api_name, "gl")) {
 		g_api = API_GL;
 		g_command_prefix = "gl";
 		g_enumeration_prefix = "GL_";
 		g_api_print_name = "OpenGL";
+		g_variant_name = "glcore";
+		xml_name = "gl.xml";
 	} else if (!strcmp(g_api_name, "egl")) {
 		g_api = API_EGL;
 		g_command_prefix = "egl";
 		g_enumeration_prefix = "EGL_";
 		g_api_print_name = "EGL";
+		g_variant_name = g_api_name;
+		xml_name = "egl.xml";
+	} else if (!strcmp(g_api_name, "gles2")) {
+		g_api = API_GLES2;
+		g_command_prefix = "gl";
+		g_enumeration_prefix = "GL_";
+		g_api_print_name = "GLES2";
+		g_variant_name = g_api_name;
+		xml_name = "gl.xml";
 	} else {
 		fprintf(stderr, "Unrecognized API '%s'\n", g_api_name);
+		print_help(argv[0]);
 		exit(-1);
 	}
 
@@ -1055,12 +1030,12 @@ int main(int argc, char **argv)
 	if (!srcdir) {
 		srcdir = PKGDATADIR;
 	}
-	snprintf(in_filename, sizeof(in_filename), "%s/%s.xml", srcdir, g_api_name);
+	snprintf(in_filename, sizeof(in_filename), "%s/%s", srcdir, xml_name);
 #else
 	if (!srcdir) {
 		srcdir = ".";
 	}
-	snprintf(in_filename, sizeof(in_filename), "%s/%s.xml", srcdir, g_api_name);
+	snprintf(in_filename, sizeof(in_filename), "%s/%s", srcdir, xml_name);
 #endif
 	err = doc.LoadFile(in_filename);
 	if (err != XML_NO_ERROR) {
@@ -1116,6 +1091,9 @@ int main(int argc, char **argv)
 	case API_GLX:
 		min_ver = 14;
 		break;
+	case API_GLES2:
+		min_ver = 20;
+		break;
 	}
 	bindify(header_name, min_ver, header_file, source_file);