aboutsummaryrefslogtreecommitdiff
path: root/subprojects/d2tk/pugl/examples
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/d2tk/pugl/examples')
-rw-r--r--subprojects/d2tk/pugl/examples/.clang-tidy40
-rw-r--r--subprojects/d2tk/pugl/examples/cube_view.h139
-rw-r--r--subprojects/d2tk/pugl/examples/demo_utils.h124
-rw-r--r--subprojects/d2tk/pugl/examples/file_utils.c68
-rw-r--r--subprojects/d2tk/pugl/examples/file_utils.h41
-rw-r--r--subprojects/d2tk/pugl/examples/glad/glad.c1138
-rw-r--r--subprojects/d2tk/pugl/examples/glad/glad.h2127
-rw-r--r--subprojects/d2tk/pugl/examples/glad/khrplatform.h290
-rw-r--r--subprojects/d2tk/pugl/examples/meson.build80
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_cairo_demo.c261
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_cursor_demo.c169
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_cxx_demo.cpp148
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_embed_demo.c354
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_print_events.c79
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_shader_demo.c470
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_vulkan_cxx_demo.cpp1826
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_vulkan_demo.c1127
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_window_demo.c254
-rw-r--r--subprojects/d2tk/pugl/examples/rects.h79
-rw-r--r--subprojects/d2tk/pugl/examples/shader_utils.h106
-rw-r--r--subprojects/d2tk/pugl/examples/shaders/header_330.glsl4
-rw-r--r--subprojects/d2tk/pugl/examples/shaders/header_420.glsl4
-rw-r--r--subprojects/d2tk/pugl/examples/shaders/meson.build35
-rw-r--r--subprojects/d2tk/pugl/examples/shaders/rect.frag33
-rw-r--r--subprojects/d2tk/pugl/examples/shaders/rect.vert36
-rw-r--r--subprojects/d2tk/pugl/examples/sybok.hpp2325
26 files changed, 11357 insertions, 0 deletions
diff --git a/subprojects/d2tk/pugl/examples/.clang-tidy b/subprojects/d2tk/pugl/examples/.clang-tidy
new file mode 100644
index 0000000..fdfa4ea
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/.clang-tidy
@@ -0,0 +1,40 @@
+Checks: >
+ *,
+ -*-non-private-member-variables-in-classes,
+ -*avoid-c-arrays,
+ -*magic-numbers,
+ -*uppercase-literal-suffix,
+ -android-cloexec-fopen,
+ -bugprone-macro-parentheses,
+ -bugprone-reserved-identifier,
+ -bugprone-suspicious-string-compare,
+ -cert-dcl37-c,
+ -cert-dcl51-cpp,
+ -cert-flp30-c,
+ -clang-analyzer-alpha.*,
+ -clang-analyzer-security.FloatLoopCounter,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-macro-usage,
+ -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
+ -cppcoreguidelines-pro-bounds-constant-array-index,
+ -cppcoreguidelines-pro-bounds-pointer-arithmetic,
+ -cppcoreguidelines-pro-type-reinterpret-cast,
+ -cppcoreguidelines-pro-type-static-cast-downcast,
+ -cppcoreguidelines-pro-type-vararg,
+ -fuchsia-default-arguments,
+ -fuchsia-default-arguments-calls,
+ -fuchsia-overloaded-operator,
+ -google-runtime-references,
+ -hicpp-multiway-paths-covered,
+ -hicpp-named-parameter,
+ -hicpp-no-array-decay,
+ -hicpp-signed-bitwise,
+ -hicpp-vararg,
+ -llvm-header-guard,
+ -llvmlibc-*,
+ -misc-misplaced-const,
+ -modernize-use-trailing-return-type,
+ -readability-implicit-bool-conversion,
+ -readability-named-parameter,
+FormatStyle: file
+HeaderFilterRegex: 'pugl/.*|test/.*|examples/.*' \ No newline at end of file
diff --git a/subprojects/d2tk/pugl/examples/cube_view.h b/subprojects/d2tk/pugl/examples/cube_view.h
new file mode 100644
index 0000000..71ae88d
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/cube_view.h
@@ -0,0 +1,139 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef EXAMPLES_CUBE_VIEW_H
+#define EXAMPLES_CUBE_VIEW_H
+
+#define GL_SILENCE_DEPRECATION 1
+
+#include "demo_utils.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+
+#include <stdbool.h>
+
+// clang-format off
+
+static const float cubeStripVertices[] = {
+ -1.0f, 1.0f, 1.0f, // Front top left
+ 1.0f, 1.0f, 1.0f, // Front top right
+ -1.0f, -1.0f, 1.0f, // Front bottom left
+ 1.0f, -1.0f, 1.0f, // Front bottom right
+ 1.0f, -1.0f, -1.0f, // Back bottom right
+ 1.0f, 1.0f, 1.0f, // Front top right
+ 1.0f, 1.0f, -1.0f, // Back top right
+ -1.0f, 1.0f, 1.0f, // Front top left
+ -1.0f, 1.0f, -1.0f, // Back top left
+ -1.0f, -1.0f, 1.0f, // Front bottom left
+ -1.0f, -1.0f, -1.0f, // Back bottom left
+ 1.0f, -1.0f, -1.0f, // Back bottom right
+ -1.0f, 1.0f, -1.0f, // Back top left
+ 1.0f, 1.0f, -1.0f // Back top right
+};
+
+static const float cubeFrontLineLoop[] = {
+ -1.0f, 1.0f, 1.0f, // Front top left
+ 1.0f, 1.0f, 1.0f, // Front top right
+ 1.0f, -1.0f, 1.0f, // Front bottom right
+ -1.0f, -1.0f, 1.0f, // Front bottom left
+};
+
+static const float cubeBackLineLoop[] = {
+ -1.0f, 1.0f, -1.0f, // Back top left
+ 1.0f, 1.0f, -1.0f, // Back top right
+ 1.0f, -1.0f, -1.0f, // Back bottom right
+ -1.0f, -1.0f, -1.0f, // Back bottom left
+};
+
+static const float cubeSideLines[] = {
+ -1.0f, 1.0f, 1.0f, // Front top left
+ -1.0f, 1.0f, -1.0f, // Back top left
+
+ -1.0f, -1.0f, 1.0f, // Front bottom left
+ -1.0f, -1.0f, -1.0f, // Back bottom left
+
+ 1.0f, 1.0f, 1.0f, // Front top right
+ 1.0f, 1.0f, -1.0f, // Back top right
+
+ 1.0f, -1.0f, 1.0f, // Front bottom right
+ 1.0f, -1.0f, -1.0f, // Back bottom right
+};
+
+// clang-format on
+
+static inline void
+reshapeCube(const float width, const float height)
+{
+ const float aspect = width / height;
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glViewport(0, 0, (int)width, (int)height);
+
+ float projection[16];
+ perspective(projection, 1.8f, aspect, 1.0f, 100.0f);
+ glLoadMatrixf(projection);
+}
+
+static inline void
+displayCube(PuglView* const view,
+ const float distance,
+ const float xAngle,
+ const float yAngle,
+ const bool entered)
+{
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0f, 0.0f, distance * -1.0f);
+ glRotatef(xAngle, 0.0f, 1.0f, 0.0f);
+ glRotatef(yAngle, 1.0f, 0.0f, 0.0f);
+
+ const float bg = entered ? 0.2f : 0.0f;
+ glClearColor(bg, bg, bg, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (puglHasFocus(view)) {
+ // Draw cube surfaces
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, cubeStripVertices);
+ glColorPointer(3, GL_FLOAT, 0, cubeStripVertices);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 14);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glColor3f(0.0f, 0.0f, 0.0f);
+ } else {
+ glColor3f(1.0f, 1.0f, 1.0f);
+ }
+
+ // Draw cube wireframe
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, cubeFrontLineLoop);
+ glDrawArrays(GL_LINE_LOOP, 0, 4);
+ glVertexPointer(3, GL_FLOAT, 0, cubeBackLineLoop);
+ glDrawArrays(GL_LINE_LOOP, 0, 4);
+ glVertexPointer(3, GL_FLOAT, 0, cubeSideLines);
+ glDrawArrays(GL_LINES, 0, 8);
+ glDisableClientState(GL_VERTEX_ARRAY);
+}
+
+#endif // EXAMPLES_CUBE_VIEW_H
diff --git a/subprojects/d2tk/pugl/examples/demo_utils.h b/subprojects/d2tk/pugl/examples/demo_utils.h
new file mode 100644
index 0000000..2dda756
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/demo_utils.h
@@ -0,0 +1,124 @@
+/*
+ Copyright 2012-2019 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef EXAMPLES_DEMO_UTILS_H
+#define EXAMPLES_DEMO_UTILS_H
+
+#include "pugl/pugl.h"
+
+#include <math.h>
+#include <stdio.h>
+
+typedef struct {
+ double lastReportTime;
+} PuglFpsPrinter;
+
+typedef float vec4[4];
+typedef vec4 mat4[4];
+
+static inline void
+mat4Identity(mat4 m)
+{
+ for (int c = 0; c < 4; ++c) {
+ for (int r = 0; r < 4; ++r) {
+ m[c][r] = c == r ? 1.0f : 0.0f;
+ }
+ }
+}
+
+static inline void
+mat4Translate(mat4 m, const float x, const float y, const float z)
+{
+ m[3][0] = x;
+ m[3][1] = y;
+ m[3][2] = z;
+}
+
+static inline void
+mat4Mul(mat4 m, mat4 a, mat4 b)
+{
+ for (int c = 0; c < 4; ++c) {
+ for (int r = 0; r < 4; ++r) {
+ m[c][r] = 0.0f;
+ for (int k = 0; k < 4; ++k) {
+ m[c][r] += a[k][r] * b[c][k];
+ }
+ }
+ }
+}
+
+static inline void
+mat4Ortho(mat4 m,
+ const float l,
+ const float r,
+ const float b,
+ const float t,
+ const float n,
+ const float f)
+{
+ m[0][0] = 2.0f / (r - l);
+ m[0][1] = m[0][2] = m[0][3] = 0.0f;
+
+ m[1][1] = 2.0f / (t - b);
+ m[1][0] = m[1][2] = m[1][3] = 0.0f;
+
+ m[2][2] = -2.0f / (f - n);
+ m[2][0] = m[2][1] = m[2][3] = 0.0f;
+
+ m[3][0] = -(r + l) / (r - l);
+ m[3][1] = -(t + b) / (t - b);
+ m[3][2] = -(f + n) / (f - n);
+ m[3][3] = 1.0f;
+}
+
+/// Calculate a projection matrix for a given perspective
+static inline void
+perspective(float* m, float fov, float aspect, float zNear, float zFar)
+{
+ const float h = tanf(fov);
+ const float w = h / aspect;
+ const float depth = zNear - zFar;
+ const float q = (zFar + zNear) / depth;
+ const float qn = 2 * zFar * zNear / depth;
+
+ // clang-format off
+ m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0;
+ m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0;
+ m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1;
+ m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0;
+ // clang-format on
+}
+
+static inline void
+puglPrintFps(const PuglWorld* world,
+ PuglFpsPrinter* printer,
+ unsigned* const framesDrawn)
+{
+ const double thisTime = puglGetTime(world);
+ if (thisTime > printer->lastReportTime + 5) {
+ const double fps = *framesDrawn / (thisTime - printer->lastReportTime);
+ fprintf(stderr,
+ "FPS: %.2f (%u frames in %.0f seconds)\n",
+ fps,
+ *framesDrawn,
+ thisTime - printer->lastReportTime);
+
+ printer->lastReportTime = thisTime;
+ *framesDrawn = 0;
+ }
+}
+
+#endif // EXAMPLES_DEMO_UTILS_H
diff --git a/subprojects/d2tk/pugl/examples/file_utils.c b/subprojects/d2tk/pugl/examples/file_utils.c
new file mode 100644
index 0000000..8ecbca4
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/file_utils.c
@@ -0,0 +1,68 @@
+/*
+ Copyright 2019-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#if !defined(__APPLE__) && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+#endif
+
+#include "file_utils.h"
+
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+# define F_OK 0
+#else
+# include <libgen.h>
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char*
+resourcePath(const char* const programPath, const char* const name)
+{
+ char* const binary = strdup(programPath);
+
+#ifdef _WIN32
+ char programDir[_MAX_DIR];
+ _splitpath(binary, programDir, NULL, NULL, NULL);
+ _splitpath(binary, NULL, programDir + strlen(programDir), NULL, NULL);
+ programDir[strlen(programDir) - 1] = '\0';
+#else
+ char* const programDir = dirname(binary);
+#endif
+
+ const size_t programDirLen = strlen(programDir);
+ const size_t nameLen = strlen(name);
+ const size_t totalLen = programDirLen + nameLen + 4;
+
+ char* const programRelative = (char*)calloc(totalLen, 1);
+ snprintf(programRelative, totalLen, "%s/%s", programDir, name);
+ if (!access(programRelative, F_OK)) {
+ free(binary);
+ return programRelative;
+ }
+
+ free(programRelative);
+ free(binary);
+
+ const size_t sysPathLen = strlen(PUGL_DATA_DIR) + nameLen + 4;
+ char* const sysPath = (char*)calloc(sysPathLen, 1);
+ snprintf(sysPath, sysPathLen, "%s/%s", PUGL_DATA_DIR, name);
+ return sysPath;
+}
diff --git a/subprojects/d2tk/pugl/examples/file_utils.h b/subprojects/d2tk/pugl/examples/file_utils.h
new file mode 100644
index 0000000..1530157
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/file_utils.h
@@ -0,0 +1,41 @@
+/*
+ Copyright 2019-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef EXAMPLES_FILE_UTILS_H
+#define EXAMPLES_FILE_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Return the path to a resource file.
+
+ This takes a name like "shaders/something.glsl" and returns the actual
+ path that can be used to load that resource, which may be relative to the
+ current executable (for running in bundles or the build directory), or a
+ shared system directory for installs.
+
+ The returned path must be freed with free().
+*/
+char*
+resourcePath(const char* programPath, const char* name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // EXAMPLES_FILE_UTILS_H
diff --git a/subprojects/d2tk/pugl/examples/glad/glad.c b/subprojects/d2tk/pugl/examples/glad/glad.c
new file mode 100644
index 0000000..38f442c
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/glad/glad.c
@@ -0,0 +1,1138 @@
+/*
+
+ OpenGL loader generated by glad 0.1.32 on -.
+
+ Language/Generator: C/C++
+ Specification: gl
+ APIs: gl=3.3
+ Profile: core
+ Extensions:
+
+ Loader: True
+ Local files: True
+ Omit khrplatform: False
+ Reproducible: True
+
+ Commandline:
+ --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --local-files --extensions=""
+ Online:
+ https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "glad.h"
+
+static void* get_proc(const char *namez);
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#undef APIENTRY
+#include <windows.h>
+static HMODULE libGL;
+
+typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*);
+static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
+
+#ifdef _MSC_VER
+#ifdef __has_include
+ #if __has_include(<winapifamily.h>)
+ #define HAVE_WINAPIFAMILY 1
+ #endif
+#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
+ #define HAVE_WINAPIFAMILY 1
+#endif
+#endif
+
+#ifdef HAVE_WINAPIFAMILY
+ #include <winapifamily.h>
+ #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+ #define IS_UWP 1
+ #endif
+#endif
+
+static
+int open_gl(void) {
+#ifndef IS_UWP
+ libGL = LoadLibraryW(L"opengl32.dll");
+ if(libGL != NULL) {
+ void (* tmp)(void);
+ tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress");
+ gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp;
+ return gladGetProcAddressPtr != NULL;
+ }
+#endif
+
+ return 0;
+}
+
+static
+void close_gl(void) {
+ if(libGL != NULL) {
+ FreeLibrary((HMODULE) libGL);
+ libGL = NULL;
+ }
+}
+#else
+#include <dlfcn.h>
+static void* libGL;
+
+#if !defined(__APPLE__) && !defined(__HAIKU__)
+typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
+static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
+#endif
+
+static
+int open_gl(void) {
+#ifdef __APPLE__
+ static const char *NAMES[] = {
+ "../Frameworks/OpenGL.framework/OpenGL",
+ "/Library/Frameworks/OpenGL.framework/OpenGL",
+ "/System/Library/Frameworks/OpenGL.framework/OpenGL",
+ "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
+ };
+#else
+ static const char *NAMES[] = {"libGL.so.1", "libGL.so"};
+#endif
+
+ unsigned int index = 0;
+ for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {
+ libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);
+
+ if(libGL != NULL) {
+#if defined(__APPLE__) || defined(__HAIKU__)
+ return 1;
+#else
+ gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
+ "glXGetProcAddressARB");
+ return gladGetProcAddressPtr != NULL;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static
+void close_gl(void) {
+ if(libGL != NULL) {
+ dlclose(libGL);
+ libGL = NULL;
+ }
+}
+#endif
+
+static
+void* get_proc(const char *namez) {
+ void* result = NULL;
+ if(libGL == NULL) return NULL;
+
+#if !defined(__APPLE__) && !defined(__HAIKU__)
+ if(gladGetProcAddressPtr != NULL) {
+ result = gladGetProcAddressPtr(namez);
+ }
+#endif
+ if(result == NULL) {
+#if defined(_WIN32) || defined(__CYGWIN__)
+ result = (void*)GetProcAddress((HMODULE) libGL, namez);
+#else
+ result = dlsym(libGL, namez);
+#endif
+ }
+
+ return result;
+}
+
+int gladLoadGL(void) {
+ int status = 0;
+
+ if(open_gl()) {
+ status = gladLoadGLLoader(&get_proc);
+ close_gl();
+ }
+
+ return status;
+}
+
+struct gladGLversionStruct GLVersion = { 0, 0 };
+
+#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
+#define _GLAD_IS_SOME_NEW_VERSION 1
+#endif
+
+static int max_loaded_major;
+static int max_loaded_minor;
+
+static const char *exts = NULL;
+static int num_exts_i = 0;
+static char **exts_i = NULL;
+
+static int get_exts(void) {
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ if(max_loaded_major < 3) {
+#endif
+ exts = (const char *)glGetString(GL_EXTENSIONS);
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ } else {
+ unsigned int index;
+
+ num_exts_i = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
+ if (num_exts_i > 0) {
+ exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i));
+ }
+
+ if (exts_i == NULL) {
+ return 0;
+ }
+
+ for(index = 0; index < (unsigned)num_exts_i; index++) {
+ const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index);
+ size_t len = strlen(gl_str_tmp);
+
+ char *local_str = (char*)malloc((len+1) * sizeof(char));
+ if(local_str != NULL) {
+ memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char));
+ }
+ exts_i[index] = local_str;
+ }
+ }
+#endif
+ return 1;
+}
+
+static void free_exts(void) {
+ if (exts_i != NULL) {
+ int index;
+ for(index = 0; index < num_exts_i; index++) {
+ free((char *)exts_i[index]);
+ }
+ free((void *)exts_i);
+ exts_i = NULL;
+ }
+}
+
+static int has_ext(const char *ext) {
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ if(max_loaded_major < 3) {
+#endif
+ const char *extensions;
+ const char *loc;
+ const char *terminator;
+ extensions = exts;
+ if(extensions == NULL || ext == NULL) {
+ return 0;
+ }
+
+ while(1) {
+ loc = strstr(extensions, ext);
+ if(loc == NULL) {
+ return 0;
+ }
+
+ terminator = loc + strlen(ext);
+ if((loc == extensions || *(loc - 1) == ' ') &&
+ (*terminator == ' ' || *terminator == '\0')) {
+ return 1;
+ }
+ extensions = terminator;
+ }
+#ifdef _GLAD_IS_SOME_NEW_VERSION
+ } else {
+ int index;
+ if(exts_i == NULL) return 0;
+ for(index = 0; index < num_exts_i; index++) {
+ const char *e = exts_i[index];
+
+ if(exts_i[index] != NULL && strcmp(e, ext) == 0) {
+ return 1;
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+int GLAD_GL_VERSION_1_0 = 0;
+int GLAD_GL_VERSION_1_1 = 0;
+int GLAD_GL_VERSION_1_2 = 0;
+int GLAD_GL_VERSION_1_3 = 0;
+int GLAD_GL_VERSION_1_4 = 0;
+int GLAD_GL_VERSION_1_5 = 0;
+int GLAD_GL_VERSION_2_0 = 0;
+int GLAD_GL_VERSION_2_1 = 0;
+int GLAD_GL_VERSION_3_0 = 0;
+int GLAD_GL_VERSION_3_1 = 0;
+int GLAD_GL_VERSION_3_2 = 0;
+int GLAD_GL_VERSION_3_3 = 0;
+PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
+PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
+PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
+PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
+PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
+PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
+PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
+PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
+PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
+PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
+PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
+PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
+PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
+PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
+PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
+PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
+PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
+PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
+PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
+PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
+PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
+PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
+PFNGLCLEARPROC glad_glClear = NULL;
+PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
+PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
+PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
+PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
+PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
+PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
+PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
+PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
+PFNGLCOLORMASKPROC glad_glColorMask = NULL;
+PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
+PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
+PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;
+PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;
+PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;
+PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
+PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
+PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
+PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
+PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
+PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
+PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
+PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
+PFNGLCULLFACEPROC glad_glCullFace = NULL;
+PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
+PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
+PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
+PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
+PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
+PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
+PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
+PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
+PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
+PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
+PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
+PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
+PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
+PFNGLDISABLEPROC glad_glDisable = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
+PFNGLDISABLEIPROC glad_glDisablei = NULL;
+PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
+PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
+PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
+PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
+PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
+PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
+PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
+PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
+PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
+PFNGLENABLEPROC glad_glEnable = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
+PFNGLENABLEIPROC glad_glEnablei = NULL;
+PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
+PFNGLENDQUERYPROC glad_glEndQuery = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
+PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
+PFNGLFINISHPROC glad_glFinish = NULL;
+PFNGLFLUSHPROC glad_glFlush = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
+PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
+PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
+PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
+PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
+PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
+PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
+PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
+PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
+PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
+PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
+PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
+PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
+PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
+PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
+PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
+PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
+PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
+PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
+PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
+PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
+PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
+PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
+PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
+PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
+PFNGLGETERRORPROC glad_glGetError = NULL;
+PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
+PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
+PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
+PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
+PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
+PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
+PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
+PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
+PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
+PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
+PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
+PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
+PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
+PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
+PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
+PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
+PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
+PFNGLGETSTRINGPROC glad_glGetString = NULL;
+PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
+PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
+PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
+PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
+PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
+PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
+PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
+PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
+PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
+PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
+PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
+PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
+PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
+PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
+PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
+PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
+PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
+PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
+PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
+PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
+PFNGLHINTPROC glad_glHint = NULL;
+PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
+PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
+PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
+PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
+PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
+PFNGLISQUERYPROC glad_glIsQuery = NULL;
+PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
+PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
+PFNGLISSHADERPROC glad_glIsShader = NULL;
+PFNGLISSYNCPROC glad_glIsSync = NULL;
+PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
+PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
+PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
+PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
+PFNGLLOGICOPPROC glad_glLogicOp = NULL;
+PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
+PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
+PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
+PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
+PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
+PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
+PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
+PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
+PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;
+PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
+PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
+PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
+PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
+PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
+PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
+PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
+PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
+PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
+PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
+PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
+PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
+PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
+PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
+PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
+PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
+PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
+PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
+PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
+PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
+PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
+PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
+PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
+PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
+PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
+PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
+PFNGLSCISSORPROC glad_glScissor = NULL;
+PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;
+PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
+PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
+PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
+PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
+PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
+PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
+PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
+PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
+PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
+PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;
+PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;
+PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;
+PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;
+PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;
+PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;
+PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
+PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
+PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
+PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
+PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
+PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
+PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
+PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
+PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
+PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
+PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
+PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
+PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
+PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
+PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
+PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
+PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
+PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
+PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
+PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
+PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
+PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
+PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
+PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
+PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
+PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
+PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
+PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
+PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
+PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
+PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
+PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
+PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
+PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
+PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
+PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
+PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
+PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
+PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
+PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
+PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
+PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
+PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
+PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
+PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
+PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
+PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
+PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
+PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
+PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
+PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
+PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
+PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
+PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
+PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
+PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
+PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
+PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
+PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
+PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
+PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
+PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
+PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
+PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
+PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
+PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
+PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
+PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
+PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
+PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
+PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
+PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
+PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
+PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
+PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
+PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
+PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
+PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
+PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
+PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
+PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
+PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
+PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
+PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
+PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
+PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
+PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
+PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
+PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
+PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
+PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
+PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
+PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
+PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
+PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
+PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
+PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
+PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
+PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
+PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
+PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
+PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
+PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
+PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
+PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
+PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
+PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
+PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
+PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
+PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
+PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
+PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
+PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
+PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
+PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
+PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;
+PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
+PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
+PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;
+PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
+PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
+PFNGLVIEWPORTPROC glad_glViewport = NULL;
+PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
+static void load_GL_VERSION_1_0(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_0) return;
+ glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
+ glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace");
+ glad_glHint = (PFNGLHINTPROC)load("glHint");
+ glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth");
+ glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize");
+ glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode");
+ glad_glScissor = (PFNGLSCISSORPROC)load("glScissor");
+ glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf");
+ glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv");
+ glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri");
+ glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv");
+ glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D");
+ glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D");
+ glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer");
+ glad_glClear = (PFNGLCLEARPROC)load("glClear");
+ glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor");
+ glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil");
+ glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth");
+ glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask");
+ glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask");
+ glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask");
+ glad_glDisable = (PFNGLDISABLEPROC)load("glDisable");
+ glad_glEnable = (PFNGLENABLEPROC)load("glEnable");
+ glad_glFinish = (PFNGLFINISHPROC)load("glFinish");
+ glad_glFlush = (PFNGLFLUSHPROC)load("glFlush");
+ glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc");
+ glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp");
+ glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc");
+ glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp");
+ glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc");
+ glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref");
+ glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei");
+ glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer");
+ glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels");
+ glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv");
+ glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev");
+ glad_glGetError = (PFNGLGETERRORPROC)load("glGetError");
+ glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv");
+ glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv");
+ glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
+ glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage");
+ glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv");
+ glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv");
+ glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv");
+ glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv");
+ glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled");
+ glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange");
+ glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport");
+}
+static void load_GL_VERSION_1_1(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_1) return;
+ glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays");
+ glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements");
+ glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset");
+ glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D");
+ glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D");
+ glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D");
+ glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D");
+ glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D");
+ glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D");
+ glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture");
+ glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures");
+ glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures");
+ glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture");
+}
+static void load_GL_VERSION_1_2(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_2) return;
+ glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements");
+ glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D");
+ glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D");
+ glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D");
+}
+static void load_GL_VERSION_1_3(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_3) return;
+ glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture");
+ glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage");
+ glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D");
+ glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D");
+ glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D");
+ glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D");
+ glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D");
+ glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D");
+ glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage");
+}
+static void load_GL_VERSION_1_4(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_4) return;
+ glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate");
+ glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays");
+ glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements");
+ glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf");
+ glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv");
+ glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri");
+ glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv");
+ glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor");
+ glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation");
+}
+static void load_GL_VERSION_1_5(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_1_5) return;
+ glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries");
+ glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries");
+ glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery");
+ glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery");
+ glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery");
+ glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv");
+ glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv");
+ glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv");
+ glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer");
+ glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers");
+ glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers");
+ glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer");
+ glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData");
+ glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData");
+ glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData");
+ glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer");
+ glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer");
+ glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv");
+ glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv");
+}
+static void load_GL_VERSION_2_0(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_2_0) return;
+ glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate");
+ glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers");
+ glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate");
+ glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate");
+ glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate");
+ glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader");
+ glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation");
+ glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader");
+ glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram");
+ glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader");
+ glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram");
+ glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader");
+ glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader");
+ glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray");
+ glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray");
+ glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib");
+ glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform");
+ glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders");
+ glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation");
+ glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv");
+ glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog");
+ glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv");
+ glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog");
+ glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource");
+ glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation");
+ glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv");
+ glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv");
+ glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv");
+ glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv");
+ glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv");
+ glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv");
+ glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram");
+ glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader");
+ glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram");
+ glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource");
+ glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram");
+ glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f");
+ glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f");
+ glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f");
+ glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f");
+ glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i");
+ glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i");
+ glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i");
+ glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i");
+ glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv");
+ glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv");
+ glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv");
+ glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv");
+ glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv");
+ glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv");
+ glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv");
+ glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv");
+ glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv");
+ glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv");
+ glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv");
+ glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram");
+ glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d");
+ glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv");
+ glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f");
+ glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv");
+ glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s");
+ glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv");
+ glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d");
+ glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv");
+ glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f");
+ glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv");
+ glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s");
+ glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv");
+ glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d");
+ glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv");
+ glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f");
+ glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv");
+ glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s");
+ glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv");
+ glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv");
+ glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv");
+ glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv");
+ glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub");
+ glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv");
+ glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv");
+ glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv");
+ glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv");
+ glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d");
+ glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv");
+ glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f");
+ glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv");
+ glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv");
+ glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s");
+ glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv");
+ glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv");
+ glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv");
+ glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv");
+ glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer");
+}
+static void load_GL_VERSION_2_1(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_2_1) return;
+ glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv");
+ glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv");
+ glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv");
+ glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv");
+ glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv");
+ glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv");
+}
+static void load_GL_VERSION_3_0(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_0) return;
+ glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski");
+ glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v");
+ glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
+ glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei");
+ glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei");
+ glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi");
+ glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback");
+ glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback");
+ glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
+ glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
+ glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings");
+ glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying");
+ glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor");
+ glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender");
+ glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender");
+ glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer");
+ glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv");
+ glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv");
+ glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i");
+ glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i");
+ glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i");
+ glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i");
+ glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui");
+ glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui");
+ glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui");
+ glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui");
+ glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv");
+ glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv");
+ glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv");
+ glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv");
+ glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv");
+ glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv");
+ glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv");
+ glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv");
+ glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv");
+ glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv");
+ glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv");
+ glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv");
+ glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv");
+ glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation");
+ glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation");
+ glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui");
+ glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui");
+ glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui");
+ glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui");
+ glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv");
+ glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv");
+ glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv");
+ glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv");
+ glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv");
+ glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv");
+ glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv");
+ glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv");
+ glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv");
+ glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv");
+ glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv");
+ glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi");
+ glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi");
+ glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer");
+ glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer");
+ glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers");
+ glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers");
+ glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage");
+ glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv");
+ glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer");
+ glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer");
+ glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers");
+ glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers");
+ glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus");
+ glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D");
+ glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D");
+ glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D");
+ glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer");
+ glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv");
+ glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap");
+ glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer");
+ glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample");
+ glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer");
+ glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange");
+ glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange");
+ glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray");
+ glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays");
+ glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays");
+ glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray");
+}
+static void load_GL_VERSION_3_1(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_1) return;
+ glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced");
+ glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced");
+ glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer");
+ glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex");
+ glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData");
+ glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices");
+ glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv");
+ glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName");
+ glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex");
+ glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv");
+ glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName");
+ glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding");
+ glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
+ glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
+ glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
+}
+static void load_GL_VERSION_3_2(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_2) return;
+ glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex");
+ glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex");
+ glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex");
+ glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex");
+ glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex");
+ glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync");
+ glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync");
+ glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync");
+ glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync");
+ glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync");
+ glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v");
+ glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv");
+ glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v");
+ glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v");
+ glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture");
+ glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample");
+ glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample");
+ glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv");
+ glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski");
+}
+static void load_GL_VERSION_3_3(GLADloadproc load) {
+ if(!GLAD_GL_VERSION_3_3) return;
+ glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed");
+ glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex");
+ glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers");
+ glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers");
+ glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler");
+ glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler");
+ glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri");
+ glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv");
+ glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf");
+ glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv");
+ glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv");
+ glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv");
+ glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv");
+ glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv");
+ glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv");
+ glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv");
+ glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter");
+ glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v");
+ glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v");
+ glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor");
+ glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui");
+ glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv");
+ glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui");
+ glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv");
+ glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui");
+ glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv");
+ glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui");
+ glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv");
+ glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui");
+ glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv");
+ glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui");
+ glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv");
+ glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui");
+ glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv");
+ glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui");
+ glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv");
+ glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui");
+ glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv");
+ glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui");
+ glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv");
+ glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui");
+ glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv");
+ glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui");
+ glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv");
+ glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui");
+ glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv");
+ glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui");
+ glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv");
+ glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui");
+ glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv");
+ glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui");
+ glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv");
+ glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui");
+ glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv");
+ glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui");
+ glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv");
+ glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
+ glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
+}
+static int find_extensionsGL(void) {
+ if (!get_exts()) return 0;
+ (void)&has_ext;
+ free_exts();
+ return 1;
+}
+
+static void find_coreGL(void) {
+
+ /* Thank you @elmindreda
+ * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176
+ * https://github.com/glfw/glfw/blob/master/src/context.c#L36
+ */
+ int i, major, minor;
+
+ const char* version;
+ const char* prefixes[] = {
+ "OpenGL ES-CM ",
+ "OpenGL ES-CL ",
+ "OpenGL ES ",
+ NULL
+ };
+
+ version = (const char*) glGetString(GL_VERSION);
+ if (!version) return;
+
+ for (i = 0; prefixes[i]; i++) {
+ const size_t length = strlen(prefixes[i]);
+ if (strncmp(version, prefixes[i], length) == 0) {
+ version += length;
+ break;
+ }
+ }
+
+/* PR #18 */
+#ifdef _MSC_VER
+ sscanf_s(version, "%d.%d", &major, &minor);
+#else
+ sscanf(version, "%d.%d", &major, &minor);
+#endif
+
+ GLVersion.major = major; GLVersion.minor = minor;
+ max_loaded_major = major; max_loaded_minor = minor;
+ GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
+ GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
+ GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
+ GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
+ GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
+ GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
+ GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
+ GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;
+ GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
+ GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
+ GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
+ GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
+ if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) {
+ max_loaded_major = 3;
+ max_loaded_minor = 3;
+ }
+}
+
+int gladLoadGLLoader(GLADloadproc load) {
+ GLVersion.major = 0; GLVersion.minor = 0;
+ glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
+ if(glGetString == NULL) return 0;
+ if(glGetString(GL_VERSION) == NULL) return 0;
+ find_coreGL();
+ load_GL_VERSION_1_0(load);
+ load_GL_VERSION_1_1(load);
+ load_GL_VERSION_1_2(load);
+ load_GL_VERSION_1_3(load);
+ load_GL_VERSION_1_4(load);
+ load_GL_VERSION_1_5(load);
+ load_GL_VERSION_2_0(load);
+ load_GL_VERSION_2_1(load);
+ load_GL_VERSION_3_0(load);
+ load_GL_VERSION_3_1(load);
+ load_GL_VERSION_3_2(load);
+ load_GL_VERSION_3_3(load);
+
+ if (!find_extensionsGL()) return 0;
+ return GLVersion.major != 0 || GLVersion.minor != 0;
+}
+
diff --git a/subprojects/d2tk/pugl/examples/glad/glad.h b/subprojects/d2tk/pugl/examples/glad/glad.h
new file mode 100644
index 0000000..9efb229
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/glad/glad.h
@@ -0,0 +1,2127 @@
+/*
+
+ OpenGL loader generated by glad 0.1.32 on -.
+
+ Language/Generator: C/C++
+ Specification: gl
+ APIs: gl=3.3
+ Profile: core
+ Extensions:
+
+ Loader: True
+ Local files: True
+ Omit khrplatform: False
+ Reproducible: True
+
+ Commandline:
+ --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --local-files --extensions=""
+ Online:
+ https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3
+*/
+
+
+#ifndef __glad_h_
+#define __glad_h_
+
+#ifdef __gl_h_
+#error OpenGL header already included, remove this include, glad already provides it
+#endif
+#define __gl_h_
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#define APIENTRY __stdcall
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY APIENTRY
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gladGLversionStruct {
+ int major;
+ int minor;
+};
+
+typedef void* (* GLADloadproc)(const char *name);
+
+#ifndef GLAPI
+# if defined(GLAD_GLAPI_EXPORT)
+# if defined(_WIN32) || defined(__CYGWIN__)
+# if defined(GLAD_GLAPI_EXPORT_BUILD)
+# if defined(__GNUC__)
+# define GLAPI __attribute__ ((dllexport)) extern
+# else
+# define GLAPI __declspec(dllexport) extern
+# endif
+# else
+# if defined(__GNUC__)
+# define GLAPI __attribute__ ((dllimport)) extern
+# else
+# define GLAPI __declspec(dllimport) extern
+# endif
+# endif
+# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD)
+# define GLAPI __attribute__ ((visibility ("default"))) extern
+# else
+# define GLAPI extern
+# endif
+# else
+# define GLAPI extern
+# endif
+#endif
+
+GLAPI struct gladGLversionStruct GLVersion;
+
+GLAPI int gladLoadGL(void);
+
+GLAPI int gladLoadGLLoader(GLADloadproc);
+
+#include "khrplatform.h"
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef khronos_int8_t GLbyte;
+typedef khronos_uint8_t GLubyte;
+typedef khronos_int16_t GLshort;
+typedef khronos_uint16_t GLushort;
+typedef int GLint;
+typedef unsigned int GLuint;
+typedef khronos_int32_t GLclampx;
+typedef int GLsizei;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+typedef void *GLeglClientBufferEXT;
+typedef void *GLeglImageOES;
+typedef char GLchar;
+typedef char GLcharARB;
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef khronos_uint16_t GLhalf;
+typedef khronos_uint16_t GLhalfARB;
+typedef khronos_int32_t GLfixed;
+typedef khronos_intptr_t GLintptr;
+typedef khronos_intptr_t GLintptrARB;
+typedef khronos_ssize_t GLsizeiptr;
+typedef khronos_ssize_t GLsizeiptrARB;
+typedef khronos_int64_t GLint64;
+typedef khronos_int64_t GLint64EXT;
+typedef khronos_uint64_t GLuint64;
+typedef khronos_uint64_t GLuint64EXT;
+typedef struct __GLsync *GLsync;
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
+typedef unsigned short GLhalfNV;
+typedef GLintptr GLvdpauSurfaceNV;
+typedef void (APIENTRY *GLVULKANPROCNV)(void);
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#define GL_NONE 0
+#define GL_FRONT_LEFT 0x0400
+#define GL_FRONT_RIGHT 0x0401
+#define GL_BACK_LEFT 0x0402
+#define GL_BACK_RIGHT 0x0403
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_LEFT 0x0406
+#define GL_RIGHT 0x0407
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_RANGE 0x0B12
+#define GL_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINE_WIDTH_RANGE 0x0B22
+#define GL_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_POLYGON_MODE 0x0B40
+#define GL_POLYGON_SMOOTH 0x0B41
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_VIEWPORT 0x0BA2
+#define GL_DITHER 0x0BD0
+#define GL_BLEND_DST 0x0BE0
+#define GL_BLEND_SRC 0x0BE1
+#define GL_BLEND 0x0BE2
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_DRAW_BUFFER 0x0C01
+#define GL_READ_BUFFER 0x0C02
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_DOUBLEBUFFER 0x0C32
+#define GL_STEREO 0x0C33
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_UNPACK_SWAP_BYTES 0x0CF0
+#define GL_UNPACK_LSB_FIRST 0x0CF1
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_SWAP_BYTES 0x0D00
+#define GL_PACK_LSB_FIRST 0x0D01
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_TEXTURE_1D 0x0DE0
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_TEXTURE_BORDER_COLOR 0x1004
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_CLEAR 0x1500
+#define GL_AND 0x1501
+#define GL_AND_REVERSE 0x1502
+#define GL_COPY 0x1503
+#define GL_AND_INVERTED 0x1504
+#define GL_NOOP 0x1505
+#define GL_XOR 0x1506
+#define GL_OR 0x1507
+#define GL_NOR 0x1508
+#define GL_EQUIV 0x1509
+#define GL_INVERT 0x150A
+#define GL_OR_REVERSE 0x150B
+#define GL_COPY_INVERTED 0x150C
+#define GL_OR_INVERTED 0x150D
+#define GL_NAND 0x150E
+#define GL_SET 0x150F
+#define GL_TEXTURE 0x1702
+#define GL_COLOR 0x1800
+#define GL_DEPTH 0x1801
+#define GL_STENCIL 0x1802
+#define GL_STENCIL_INDEX 0x1901
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_RED 0x1903
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_POINT 0x1B00
+#define GL_LINE 0x1B01
+#define GL_FILL 0x1B02
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_REPEAT 0x2901
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_OFFSET_POINT 0x2A01
+#define GL_POLYGON_OFFSET_LINE 0x2A02
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_1D 0x8068
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
+#define GL_TEXTURE_RED_SIZE 0x805C
+#define GL_TEXTURE_GREEN_SIZE 0x805D
+#define GL_TEXTURE_BLUE_SIZE 0x805E
+#define GL_TEXTURE_ALPHA_SIZE 0x805F
+#define GL_DOUBLE 0x140A
+#define GL_PROXY_TEXTURE_1D 0x8063
+#define GL_PROXY_TEXTURE_2D 0x8064
+#define GL_R3_G3_B2 0x2A10
+#define GL_RGB4 0x804F
+#define GL_RGB5 0x8050
+#define GL_RGB8 0x8051
+#define GL_RGB10 0x8052
+#define GL_RGB12 0x8053
+#define GL_RGB16 0x8054
+#define GL_RGBA2 0x8055
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGBA8 0x8058
+#define GL_RGB10_A2 0x8059
+#define GL_RGBA12 0x805A
+#define GL_RGBA16 0x805B
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_TEXTURE_3D 0x806F
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_CLAMP_TO_BORDER 0x812D
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_DEPTH_COMPONENT32 0x81A7
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_TEXTURE_LOD_BIAS 0x8501
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+#define GL_TEXTURE_DEPTH_SIZE 0x884A
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_BLEND_COLOR 0x8005
+#define GL_BLEND_EQUATION 0x8009
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_MIN 0x8007
+#define GL_MAX 0x8008
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+#define GL_QUERY_COUNTER_BITS 0x8864
+#define GL_CURRENT_QUERY 0x8865
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_READ_WRITE 0x88BA
+#define GL_BUFFER_ACCESS 0x88BB
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_STREAM_COPY 0x88E2
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STATIC_READ 0x88E5
+#define GL_STATIC_COPY 0x88E6
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_SAMPLES_PASSED 0x8914
+#define GL_SRC1_ALPHA 0x8589
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_MAX_VARYING_FLOATS 0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLER_1D_SHADOW 0x8B61
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_DELETE_STATUS 0x8B80
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
+#define GL_FLOAT_MAT2x3 0x8B65
+#define GL_FLOAT_MAT2x4 0x8B66
+#define GL_FLOAT_MAT3x2 0x8B67
+#define GL_FLOAT_MAT3x4 0x8B68
+#define GL_FLOAT_MAT4x2 0x8B69
+#define GL_FLOAT_MAT4x3 0x8B6A
+#define GL_SRGB 0x8C40
+#define GL_SRGB8 0x8C41
+#define GL_SRGB_ALPHA 0x8C42
+#define GL_SRGB8_ALPHA8 0x8C43
+#define GL_COMPRESSED_SRGB 0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
+#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+#define GL_CLIP_DISTANCE0 0x3000
+#define GL_CLIP_DISTANCE1 0x3001
+#define GL_CLIP_DISTANCE2 0x3002
+#define GL_CLIP_DISTANCE3 0x3003
+#define GL_CLIP_DISTANCE4 0x3004
+#define GL_CLIP_DISTANCE5 0x3005
+#define GL_CLIP_DISTANCE6 0x3006
+#define GL_CLIP_DISTANCE7 0x3007
+#define GL_MAX_CLIP_DISTANCES 0x0D32
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MINOR_VERSION 0x821C
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_CONTEXT_FLAGS 0x821E
+#define GL_COMPRESSED_RED 0x8225
+#define GL_COMPRESSED_RG 0x8226
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_RGBA32F 0x8814
+#define GL_RGB32F 0x8815
+#define GL_RGBA16F 0x881A
+#define GL_RGB16F 0x881B
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
+#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
+#define GL_CLAMP_READ_COLOR 0x891C
+#define GL_FIXED_ONLY 0x891D
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_TEXTURE_1D_ARRAY 0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
+#define GL_TEXTURE_2D_ARRAY 0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_R11F_G11F_B10F 0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+#define GL_RGB9_E5 0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+#define GL_TEXTURE_SHARED_SIZE 0x8C3F
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_PRIMITIVES_GENERATED 0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_RASTERIZER_DISCARD 0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS 0x8C8C
+#define GL_SEPARATE_ATTRIBS 0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_RGBA32UI 0x8D70
+#define GL_RGB32UI 0x8D71
+#define GL_RGBA16UI 0x8D76
+#define GL_RGB16UI 0x8D77
+#define GL_RGBA8UI 0x8D7C
+#define GL_RGB8UI 0x8D7D
+#define GL_RGBA32I 0x8D82
+#define GL_RGB32I 0x8D83
+#define GL_RGBA16I 0x8D88
+#define GL_RGB16I 0x8D89
+#define GL_RGBA8I 0x8D8E
+#define GL_RGB8I 0x8D8F
+#define GL_RED_INTEGER 0x8D94
+#define GL_GREEN_INTEGER 0x8D95
+#define GL_BLUE_INTEGER 0x8D96
+#define GL_RGB_INTEGER 0x8D98
+#define GL_RGBA_INTEGER 0x8D99
+#define GL_BGR_INTEGER 0x8D9A
+#define GL_BGRA_INTEGER 0x8D9B
+#define GL_SAMPLER_1D_ARRAY 0x8DC0
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#define GL_INT_SAMPLER_1D 0x8DC9
+#define GL_INT_SAMPLER_2D 0x8DCA
+#define GL_INT_SAMPLER_3D 0x8DCB
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_QUERY_WAIT 0x8E13
+#define GL_QUERY_NO_WAIT 0x8E14
+#define GL_QUERY_BY_REGION_WAIT 0x8E15
+#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
+#define GL_BUFFER_ACCESS_FLAGS 0x911F
+#define GL_BUFFER_MAP_LENGTH 0x9120
+#define GL_BUFFER_MAP_OFFSET 0x9121
+#define GL_DEPTH_COMPONENT32F 0x8CAC
+#define GL_DEPTH32F_STENCIL8 0x8CAD
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_DEFAULT 0x8218
+#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#define GL_DEPTH_STENCIL 0x84F9
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#define GL_DEPTH24_STENCIL8 0x88F0
+#define GL_TEXTURE_STENCIL_SIZE 0x88F1
+#define GL_TEXTURE_RED_TYPE 0x8C10
+#define GL_TEXTURE_GREEN_TYPE 0x8C11
+#define GL_TEXTURE_BLUE_TYPE 0x8C12
+#define GL_TEXTURE_ALPHA_TYPE 0x8C13
+#define GL_TEXTURE_DEPTH_TYPE 0x8C16
+#define GL_UNSIGNED_NORMALIZED 0x8C17
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_COLOR_ATTACHMENT1 0x8CE1
+#define GL_COLOR_ATTACHMENT2 0x8CE2
+#define GL_COLOR_ATTACHMENT3 0x8CE3
+#define GL_COLOR_ATTACHMENT4 0x8CE4
+#define GL_COLOR_ATTACHMENT5 0x8CE5
+#define GL_COLOR_ATTACHMENT6 0x8CE6
+#define GL_COLOR_ATTACHMENT7 0x8CE7
+#define GL_COLOR_ATTACHMENT8 0x8CE8
+#define GL_COLOR_ATTACHMENT9 0x8CE9
+#define GL_COLOR_ATTACHMENT10 0x8CEA
+#define GL_COLOR_ATTACHMENT11 0x8CEB
+#define GL_COLOR_ATTACHMENT12 0x8CEC
+#define GL_COLOR_ATTACHMENT13 0x8CED
+#define GL_COLOR_ATTACHMENT14 0x8CEE
+#define GL_COLOR_ATTACHMENT15 0x8CEF
+#define GL_COLOR_ATTACHMENT16 0x8CF0
+#define GL_COLOR_ATTACHMENT17 0x8CF1
+#define GL_COLOR_ATTACHMENT18 0x8CF2
+#define GL_COLOR_ATTACHMENT19 0x8CF3
+#define GL_COLOR_ATTACHMENT20 0x8CF4
+#define GL_COLOR_ATTACHMENT21 0x8CF5
+#define GL_COLOR_ATTACHMENT22 0x8CF6
+#define GL_COLOR_ATTACHMENT23 0x8CF7
+#define GL_COLOR_ATTACHMENT24 0x8CF8
+#define GL_COLOR_ATTACHMENT25 0x8CF9
+#define GL_COLOR_ATTACHMENT26 0x8CFA
+#define GL_COLOR_ATTACHMENT27 0x8CFB
+#define GL_COLOR_ATTACHMENT28 0x8CFC
+#define GL_COLOR_ATTACHMENT29 0x8CFD
+#define GL_COLOR_ATTACHMENT30 0x8CFE
+#define GL_COLOR_ATTACHMENT31 0x8CFF
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_STENCIL_INDEX1 0x8D46
+#define GL_STENCIL_INDEX4 0x8D47
+#define GL_STENCIL_INDEX8 0x8D48
+#define GL_STENCIL_INDEX16 0x8D49
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_MAX_SAMPLES 0x8D57
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_HALF_FLOAT 0x140B
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_WRITE_BIT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
+#define GL_RG 0x8227
+#define GL_RG_INTEGER 0x8228
+#define GL_R8 0x8229
+#define GL_R16 0x822A
+#define GL_RG8 0x822B
+#define GL_RG16 0x822C
+#define GL_R16F 0x822D
+#define GL_R32F 0x822E
+#define GL_RG16F 0x822F
+#define GL_RG32F 0x8230
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#define GL_SAMPLER_2D_RECT 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
+#define GL_SAMPLER_BUFFER 0x8DC2
+#define GL_INT_SAMPLER_2D_RECT 0x8DCD
+#define GL_INT_SAMPLER_BUFFER 0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
+#define GL_TEXTURE_BUFFER 0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
+#define GL_TEXTURE_RECTANGLE 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
+#define GL_R8_SNORM 0x8F94
+#define GL_RG8_SNORM 0x8F95
+#define GL_RGB8_SNORM 0x8F96
+#define GL_RGBA8_SNORM 0x8F97
+#define GL_R16_SNORM 0x8F98
+#define GL_RG16_SNORM 0x8F99
+#define GL_RGB16_SNORM 0x8F9A
+#define GL_RGBA16_SNORM 0x8F9B
+#define GL_SIGNED_NORMALIZED 0x8F9C
+#define GL_PRIMITIVE_RESTART 0x8F9D
+#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+#define GL_UNIFORM_BUFFER 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING 0x8A28
+#define GL_UNIFORM_BUFFER_START 0x8A29
+#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
+#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
+#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#define GL_UNIFORM_TYPE 0x8A37
+#define GL_UNIFORM_SIZE 0x8A38
+#define GL_UNIFORM_NAME_LENGTH 0x8A39
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#define GL_UNIFORM_OFFSET 0x8A3B
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_INVALID_INDEX 0xFFFFFFFF
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_LINES_ADJACENCY 0x000A
+#define GL_LINE_STRIP_ADJACENCY 0x000B
+#define GL_TRIANGLES_ADJACENCY 0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
+#define GL_PROGRAM_POINT_SIZE 0x8642
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
+#define GL_GEOMETRY_SHADER 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT 0x8916
+#define GL_GEOMETRY_INPUT_TYPE 0x8917
+#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
+#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_DEPTH_CLAMP 0x864F
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
+#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
+#define GL_LAST_VERTEX_CONVENTION 0x8E4E
+#define GL_PROVOKING_VERTEX 0x8E4F
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
+#define GL_OBJECT_TYPE 0x9112
+#define GL_SYNC_CONDITION 0x9113
+#define GL_SYNC_STATUS 0x9114
+#define GL_SYNC_FLAGS 0x9115
+#define GL_SYNC_FENCE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#define GL_UNSIGNALED 0x9118
+#define GL_SIGNALED 0x9119
+#define GL_ALREADY_SIGNALED 0x911A
+#define GL_TIMEOUT_EXPIRED 0x911B
+#define GL_CONDITION_SATISFIED 0x911C
+#define GL_WAIT_FAILED 0x911D
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#define GL_SAMPLE_POSITION 0x8E50
+#define GL_SAMPLE_MASK 0x8E51
+#define GL_SAMPLE_MASK_VALUE 0x8E52
+#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
+#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
+#define GL_TEXTURE_SAMPLES 0x9106
+#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
+#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
+#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
+#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
+#define GL_MAX_INTEGER_SAMPLES 0x9110
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
+#define GL_SRC1_COLOR 0x88F9
+#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
+#define GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GL_SAMPLER_BINDING 0x8919
+#define GL_RGB10_A2UI 0x906F
+#define GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_TIME_ELAPSED 0x88BF
+#define GL_TIMESTAMP 0x8E28
+#define GL_INT_2_10_10_10_REV 0x8D9F
+#ifndef GL_VERSION_1_0
+#define GL_VERSION_1_0 1
+GLAPI int GLAD_GL_VERSION_1_0;
+typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode);
+GLAPI PFNGLCULLFACEPROC glad_glCullFace;
+#define glCullFace glad_glCullFace
+typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode);
+GLAPI PFNGLFRONTFACEPROC glad_glFrontFace;
+#define glFrontFace glad_glFrontFace
+typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode);
+GLAPI PFNGLHINTPROC glad_glHint;
+#define glHint glad_glHint
+typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width);
+GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth;
+#define glLineWidth glad_glLineWidth
+typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size);
+GLAPI PFNGLPOINTSIZEPROC glad_glPointSize;
+#define glPointSize glad_glPointSize
+typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);
+GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode;
+#define glPolygonMode glad_glPolygonMode
+typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLSCISSORPROC glad_glScissor;
+#define glScissor glad_glScissor
+typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);
+GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
+#define glTexParameterf glad_glTexParameterf
+typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params);
+GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
+#define glTexParameterfv glad_glTexParameterfv
+typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
+GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
+#define glTexParameteri glad_glTexParameteri
+typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params);
+GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
+#define glTexParameteriv glad_glTexParameteriv
+typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
+#define glTexImage1D glad_glTexImage1D
+typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
+#define glTexImage2D glad_glTexImage2D
+typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf);
+GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
+#define glDrawBuffer glad_glDrawBuffer
+typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask);
+GLAPI PFNGLCLEARPROC glad_glClear;
+#define glClear glad_glClear
+typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI PFNGLCLEARCOLORPROC glad_glClearColor;
+#define glClearColor glad_glClearColor
+typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s);
+GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil;
+#define glClearStencil glad_glClearStencil
+typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth);
+GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth;
+#define glClearDepth glad_glClearDepth
+typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask);
+GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask;
+#define glStencilMask glad_glStencilMask
+typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GLAPI PFNGLCOLORMASKPROC glad_glColorMask;
+#define glColorMask glad_glColorMask
+typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag);
+GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask;
+#define glDepthMask glad_glDepthMask
+typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap);
+GLAPI PFNGLDISABLEPROC glad_glDisable;
+#define glDisable glad_glDisable
+typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap);
+GLAPI PFNGLENABLEPROC glad_glEnable;
+#define glEnable glad_glEnable
+typedef void (APIENTRYP PFNGLFINISHPROC)(void);
+GLAPI PFNGLFINISHPROC glad_glFinish;
+#define glFinish glad_glFinish
+typedef void (APIENTRYP PFNGLFLUSHPROC)(void);
+GLAPI PFNGLFLUSHPROC glad_glFlush;
+#define glFlush glad_glFlush
+typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);
+GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc;
+#define glBlendFunc glad_glBlendFunc
+typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode);
+GLAPI PFNGLLOGICOPPROC glad_glLogicOp;
+#define glLogicOp glad_glLogicOp
+typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);
+GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc;
+#define glStencilFunc glad_glStencilFunc
+typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);
+GLAPI PFNGLSTENCILOPPROC glad_glStencilOp;
+#define glStencilOp glad_glStencilOp
+typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func);
+GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc;
+#define glDepthFunc glad_glDepthFunc
+typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);
+GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref;
+#define glPixelStoref glad_glPixelStoref
+typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);
+GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei;
+#define glPixelStorei glad_glPixelStorei
+typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src);
+GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer;
+#define glReadBuffer glad_glReadBuffer
+typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
+GLAPI PFNGLREADPIXELSPROC glad_glReadPixels;
+#define glReadPixels glad_glReadPixels
+typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data);
+GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
+#define glGetBooleanv glad_glGetBooleanv
+typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data);
+GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev;
+#define glGetDoublev glad_glGetDoublev
+typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void);
+GLAPI PFNGLGETERRORPROC glad_glGetError;
+#define glGetError glad_glGetError
+typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data);
+GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv;
+#define glGetFloatv glad_glGetFloatv
+typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data);
+GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv;
+#define glGetIntegerv glad_glGetIntegerv
+typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name);
+GLAPI PFNGLGETSTRINGPROC glad_glGetString;
+#define glGetString glad_glGetString
+typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
+#define glGetTexImage glad_glGetTexImage
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params);
+GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
+#define glGetTexParameterfv glad_glGetTexParameterfv
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
+GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
+#define glGetTexParameteriv glad_glGetTexParameteriv
+typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params);
+GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
+#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv
+typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params);
+GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
+#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv
+typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap);
+GLAPI PFNGLISENABLEDPROC glad_glIsEnabled;
+#define glIsEnabled glad_glIsEnabled
+typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f);
+GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange;
+#define glDepthRange glad_glDepthRange
+typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLVIEWPORTPROC glad_glViewport;
+#define glViewport glad_glViewport
+#endif
+#ifndef GL_VERSION_1_1
+#define GL_VERSION_1_1 1
+GLAPI int GLAD_GL_VERSION_1_1;
+typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
+GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays;
+#define glDrawArrays glad_glDrawArrays
+typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices);
+GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements;
+#define glDrawElements glad_glDrawElements
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);
+GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
+#define glPolygonOffset glad_glPolygonOffset
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
+#define glCopyTexImage1D glad_glCopyTexImage1D
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
+#define glCopyTexImage2D glad_glCopyTexImage2D
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
+#define glCopyTexSubImage1D glad_glCopyTexSubImage1D
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
+#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
+#define glTexSubImage1D glad_glTexSubImage1D
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
+#define glTexSubImage2D glad_glTexSubImage2D
+typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);
+GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture;
+#define glBindTexture glad_glBindTexture
+typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures);
+GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
+#define glDeleteTextures glad_glDeleteTextures
+typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures);
+GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures;
+#define glGenTextures glad_glGenTextures
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture);
+GLAPI PFNGLISTEXTUREPROC glad_glIsTexture;
+#define glIsTexture glad_glIsTexture
+#endif
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+GLAPI int GLAD_GL_VERSION_1_2;
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
+#define glDrawRangeElements glad_glDrawRangeElements
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
+#define glTexImage3D glad_glTexImage3D
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
+#define glTexSubImage3D glad_glTexSubImage3D
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
+#define glCopyTexSubImage3D glad_glCopyTexSubImage3D
+#endif
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+GLAPI int GLAD_GL_VERSION_1_3;
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture);
+GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
+#define glActiveTexture glad_glActiveTexture
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);
+GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
+#define glSampleCoverage glad_glSampleCoverage
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
+#define glCompressedTexImage3D glad_glCompressedTexImage3D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
+#define glCompressedTexImage2D glad_glCompressedTexImage2D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
+#define glCompressedTexImage1D glad_glCompressedTexImage1D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
+#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
+#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
+#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img);
+GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
+#define glGetCompressedTexImage glad_glGetCompressedTexImage
+#endif
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+GLAPI int GLAD_GL_VERSION_1_4;
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
+#define glBlendFuncSeparate glad_glBlendFuncSeparate
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
+GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
+#define glMultiDrawArrays glad_glMultiDrawArrays
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
+GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
+#define glMultiDrawElements glad_glMultiDrawElements
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);
+GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
+#define glPointParameterf glad_glPointParameterf
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params);
+GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
+#define glPointParameterfv glad_glPointParameterfv
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);
+GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
+#define glPointParameteri glad_glPointParameteri
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params);
+GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
+#define glPointParameteriv glad_glPointParameteriv
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor;
+#define glBlendColor glad_glBlendColor
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode);
+GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
+#define glBlendEquation glad_glBlendEquation
+#endif
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+GLAPI int GLAD_GL_VERSION_1_5;
+typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids);
+GLAPI PFNGLGENQUERIESPROC glad_glGenQueries;
+#define glGenQueries glad_glGenQueries
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids);
+GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
+#define glDeleteQueries glad_glDeleteQueries
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id);
+GLAPI PFNGLISQUERYPROC glad_glIsQuery;
+#define glIsQuery glad_glIsQuery
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);
+GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery;
+#define glBeginQuery glad_glBeginQuery
+typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target);
+GLAPI PFNGLENDQUERYPROC glad_glEndQuery;
+#define glEndQuery glad_glEndQuery
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params);
+GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv;
+#define glGetQueryiv glad_glGetQueryiv
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params);
+GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
+#define glGetQueryObjectiv glad_glGetQueryObjectiv
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params);
+GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
+#define glGetQueryObjectuiv glad_glGetQueryObjectuiv
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
+GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer;
+#define glBindBuffer glad_glBindBuffer
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers);
+GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
+#define glDeleteBuffers glad_glDeleteBuffers
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers);
+GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers;
+#define glGenBuffers glad_glGenBuffers
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer);
+GLAPI PFNGLISBUFFERPROC glad_glIsBuffer;
+#define glIsBuffer glad_glIsBuffer
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI PFNGLBUFFERDATAPROC glad_glBufferData;
+#define glBufferData glad_glBufferData
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
+#define glBufferSubData glad_glBufferSubData
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data);
+GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
+#define glGetBufferSubData glad_glGetBufferSubData
+typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);
+GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer;
+#define glMapBuffer glad_glMapBuffer
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target);
+GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
+#define glUnmapBuffer glad_glUnmapBuffer
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
+GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
+#define glGetBufferParameteriv glad_glGetBufferParameteriv
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params);
+GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
+#define glGetBufferPointerv glad_glGetBufferPointerv
+#endif
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+GLAPI int GLAD_GL_VERSION_2_0;
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);
+GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
+#define glBlendEquationSeparate glad_glBlendEquationSeparate
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs);
+GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
+#define glDrawBuffers glad_glDrawBuffers
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
+#define glStencilOpSeparate glad_glStencilOpSeparate
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);
+GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
+#define glStencilFuncSeparate glad_glStencilFuncSeparate
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);
+GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
+#define glStencilMaskSeparate glad_glStencilMaskSeparate
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
+GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader;
+#define glAttachShader glad_glAttachShader
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name);
+GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
+#define glBindAttribLocation glad_glBindAttribLocation
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader);
+GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader;
+#define glCompileShader glad_glCompileShader
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void);
+GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
+#define glCreateProgram glad_glCreateProgram
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type);
+GLAPI PFNGLCREATESHADERPROC glad_glCreateShader;
+#define glCreateShader glad_glCreateShader
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program);
+GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
+#define glDeleteProgram glad_glDeleteProgram
+typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader);
+GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader;
+#define glDeleteShader glad_glDeleteShader
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);
+GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader;
+#define glDetachShader glad_glDetachShader
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);
+GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
+#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
+GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
+#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
+#define glGetActiveAttrib glad_glGetActiveAttrib
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
+#define glGetActiveUniform glad_glGetActiveUniform
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
+#define glGetAttachedShaders glad_glGetAttachedShaders
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name);
+GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
+#define glGetAttribLocation glad_glGetAttribLocation
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params);
+GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
+#define glGetProgramiv glad_glGetProgramiv
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
+#define glGetProgramInfoLog glad_glGetProgramInfoLog
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params);
+GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv;
+#define glGetShaderiv glad_glGetShaderiv
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
+#define glGetShaderInfoLog glad_glGetShaderInfoLog
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
+#define glGetShaderSource glad_glGetShaderSource
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name);
+GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
+#define glGetUniformLocation glad_glGetUniformLocation
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params);
+GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
+#define glGetUniformfv glad_glGetUniformfv
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params);
+GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
+#define glGetUniformiv glad_glGetUniformiv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params);
+GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
+#define glGetVertexAttribdv glad_glGetVertexAttribdv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params);
+GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
+#define glGetVertexAttribfv glad_glGetVertexAttribfv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params);
+GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
+#define glGetVertexAttribiv glad_glGetVertexAttribiv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer);
+GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
+#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program);
+GLAPI PFNGLISPROGRAMPROC glad_glIsProgram;
+#define glIsProgram glad_glIsProgram
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader);
+GLAPI PFNGLISSHADERPROC glad_glIsShader;
+#define glIsShader glad_glIsShader
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program);
+GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram;
+#define glLinkProgram glad_glLinkProgram
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource;
+#define glShaderSource glad_glShaderSource
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program);
+GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram;
+#define glUseProgram glad_glUseProgram
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);
+GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f;
+#define glUniform1f glad_glUniform1f
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);
+GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f;
+#define glUniform2f glad_glUniform2f
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f;
+#define glUniform3f glad_glUniform3f
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f;
+#define glUniform4f glad_glUniform4f
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0);
+GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i;
+#define glUniform1i glad_glUniform1i
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);
+GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i;
+#define glUniform2i glad_glUniform2i
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i;
+#define glUniform3i glad_glUniform3i
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i;
+#define glUniform4i glad_glUniform4i
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value);
+GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv;
+#define glUniform1fv glad_glUniform1fv
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value);
+GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv;
+#define glUniform2fv glad_glUniform2fv
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value);
+GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv;
+#define glUniform3fv glad_glUniform3fv
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value);
+GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv;
+#define glUniform4fv glad_glUniform4fv
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value);
+GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv;
+#define glUniform1iv glad_glUniform1iv
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value);
+GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv;
+#define glUniform2iv glad_glUniform2iv
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value);
+GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv;
+#define glUniform3iv glad_glUniform3iv
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value);
+GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv;
+#define glUniform4iv glad_glUniform4iv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
+#define glUniformMatrix2fv glad_glUniformMatrix2fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
+#define glUniformMatrix3fv glad_glUniformMatrix3fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
+#define glUniformMatrix4fv glad_glUniformMatrix4fv
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program);
+GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
+#define glValidateProgram glad_glValidateProgram
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);
+GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
+#define glVertexAttrib1d glad_glVertexAttrib1d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v);
+GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
+#define glVertexAttrib1dv glad_glVertexAttrib1dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);
+GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
+#define glVertexAttrib1f glad_glVertexAttrib1f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v);
+GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
+#define glVertexAttrib1fv glad_glVertexAttrib1fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);
+GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
+#define glVertexAttrib1s glad_glVertexAttrib1s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v);
+GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
+#define glVertexAttrib1sv glad_glVertexAttrib1sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);
+GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
+#define glVertexAttrib2d glad_glVertexAttrib2d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v);
+GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
+#define glVertexAttrib2dv glad_glVertexAttrib2dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);
+GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
+#define glVertexAttrib2f glad_glVertexAttrib2f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v);
+GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
+#define glVertexAttrib2fv glad_glVertexAttrib2fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);
+GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
+#define glVertexAttrib2s glad_glVertexAttrib2s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v);
+GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
+#define glVertexAttrib2sv glad_glVertexAttrib2sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
+#define glVertexAttrib3d glad_glVertexAttrib3d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v);
+GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
+#define glVertexAttrib3dv glad_glVertexAttrib3dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
+#define glVertexAttrib3f glad_glVertexAttrib3f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v);
+GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
+#define glVertexAttrib3fv glad_glVertexAttrib3fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
+#define glVertexAttrib3s glad_glVertexAttrib3s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v);
+GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
+#define glVertexAttrib3sv glad_glVertexAttrib3sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v);
+GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
+#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v);
+GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
+#define glVertexAttrib4Niv glad_glVertexAttrib4Niv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v);
+GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
+#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
+#define glVertexAttrib4Nub glad_glVertexAttrib4Nub
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v);
+GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
+#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v);
+GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
+#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v);
+GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
+#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v);
+GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
+#define glVertexAttrib4bv glad_glVertexAttrib4bv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
+#define glVertexAttrib4d glad_glVertexAttrib4d
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v);
+GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
+#define glVertexAttrib4dv glad_glVertexAttrib4dv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
+#define glVertexAttrib4f glad_glVertexAttrib4f
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v);
+GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
+#define glVertexAttrib4fv glad_glVertexAttrib4fv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v);
+GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
+#define glVertexAttrib4iv glad_glVertexAttrib4iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
+#define glVertexAttrib4s glad_glVertexAttrib4s
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v);
+GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
+#define glVertexAttrib4sv glad_glVertexAttrib4sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v);
+GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
+#define glVertexAttrib4ubv glad_glVertexAttrib4ubv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v);
+GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
+#define glVertexAttrib4uiv glad_glVertexAttrib4uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v);
+GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
+#define glVertexAttrib4usv glad_glVertexAttrib4usv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
+#define glVertexAttribPointer glad_glVertexAttribPointer
+#endif
+#ifndef GL_VERSION_2_1
+#define GL_VERSION_2_1 1
+GLAPI int GLAD_GL_VERSION_2_1;
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
+#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
+#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
+#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
+#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
+#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
+#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv
+#endif
+#ifndef GL_VERSION_3_0
+#define GL_VERSION_3_0 1
+GLAPI int GLAD_GL_VERSION_3_0;
+typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski;
+#define glColorMaski glad_glColorMaski
+typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data);
+GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
+#define glGetBooleani_v glad_glGetBooleani_v
+typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data);
+GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
+#define glGetIntegeri_v glad_glGetIntegeri_v
+typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index);
+GLAPI PFNGLENABLEIPROC glad_glEnablei;
+#define glEnablei glad_glEnablei
+typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index);
+GLAPI PFNGLDISABLEIPROC glad_glDisablei;
+#define glDisablei glad_glDisablei
+typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index);
+GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi;
+#define glIsEnabledi glad_glIsEnabledi
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);
+GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
+#define glBeginTransformFeedback glad_glBeginTransformFeedback
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void);
+GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
+#define glEndTransformFeedback glad_glEndTransformFeedback
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
+#define glBindBufferRange glad_glBindBufferRange
+typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);
+GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
+#define glBindBufferBase glad_glBindBufferBase
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
+#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
+#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying
+typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);
+GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor;
+#define glClampColor glad_glClampColor
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);
+GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
+#define glBeginConditionalRender glad_glBeginConditionalRender
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void);
+GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
+#define glEndConditionalRender glad_glEndConditionalRender
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
+#define glVertexAttribIPointer glad_glVertexAttribIPointer
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params);
+GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
+#define glGetVertexAttribIiv glad_glGetVertexAttribIiv
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params);
+GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
+#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);
+GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
+#define glVertexAttribI1i glad_glVertexAttribI1i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);
+GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
+#define glVertexAttribI2i glad_glVertexAttribI2i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);
+GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
+#define glVertexAttribI3i glad_glVertexAttribI3i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
+#define glVertexAttribI4i glad_glVertexAttribI4i
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);
+GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
+#define glVertexAttribI1ui glad_glVertexAttribI1ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);
+GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
+#define glVertexAttribI2ui glad_glVertexAttribI2ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);
+GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
+#define glVertexAttribI3ui glad_glVertexAttribI3ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
+#define glVertexAttribI4ui glad_glVertexAttribI4ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v);
+GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
+#define glVertexAttribI1iv glad_glVertexAttribI1iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v);
+GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
+#define glVertexAttribI2iv glad_glVertexAttribI2iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v);
+GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
+#define glVertexAttribI3iv glad_glVertexAttribI3iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v);
+GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
+#define glVertexAttribI4iv glad_glVertexAttribI4iv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v);
+GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
+#define glVertexAttribI1uiv glad_glVertexAttribI1uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v);
+GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
+#define glVertexAttribI2uiv glad_glVertexAttribI2uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v);
+GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
+#define glVertexAttribI3uiv glad_glVertexAttribI3uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v);
+GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
+#define glVertexAttribI4uiv glad_glVertexAttribI4uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v);
+GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
+#define glVertexAttribI4bv glad_glVertexAttribI4bv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v);
+GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
+#define glVertexAttribI4sv glad_glVertexAttribI4sv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v);
+GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
+#define glVertexAttribI4ubv glad_glVertexAttribI4ubv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v);
+GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
+#define glVertexAttribI4usv glad_glVertexAttribI4usv
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params);
+GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
+#define glGetUniformuiv glad_glGetUniformuiv
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name);
+GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
+#define glBindFragDataLocation glad_glBindFragDataLocation
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name);
+GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
+#define glGetFragDataLocation glad_glGetFragDataLocation
+typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);
+GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui;
+#define glUniform1ui glad_glUniform1ui
+typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);
+GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui;
+#define glUniform2ui glad_glUniform2ui
+typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui;
+#define glUniform3ui glad_glUniform3ui
+typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui;
+#define glUniform4ui glad_glUniform4ui
+typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value);
+GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
+#define glUniform1uiv glad_glUniform1uiv
+typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value);
+GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
+#define glUniform2uiv glad_glUniform2uiv
+typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value);
+GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
+#define glUniform3uiv glad_glUniform3uiv
+typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value);
+GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
+#define glUniform4uiv glad_glUniform4uiv
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params);
+GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
+#define glTexParameterIiv glad_glTexParameterIiv
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params);
+GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
+#define glTexParameterIuiv glad_glTexParameterIuiv
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params);
+GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
+#define glGetTexParameterIiv glad_glGetTexParameterIiv
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params);
+GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
+#define glGetTexParameterIuiv glad_glGetTexParameterIuiv
+typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value);
+GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
+#define glClearBufferiv glad_glClearBufferiv
+typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value);
+GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
+#define glClearBufferuiv glad_glClearBufferuiv
+typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value);
+GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
+#define glClearBufferfv glad_glClearBufferfv
+typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
+#define glClearBufferfi glad_glClearBufferfi
+typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
+GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi;
+#define glGetStringi glad_glGetStringi
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);
+GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
+#define glIsRenderbuffer glad_glIsRenderbuffer
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);
+GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
+#define glBindRenderbuffer glad_glBindRenderbuffer
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers);
+GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
+#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers);
+GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
+#define glGenRenderbuffers glad_glGenRenderbuffers
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
+#define glRenderbufferStorage glad_glRenderbufferStorage
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
+GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
+#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);
+GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
+#define glIsFramebuffer glad_glIsFramebuffer
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
+GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
+#define glBindFramebuffer glad_glBindFramebuffer
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers);
+GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
+#define glDeleteFramebuffers glad_glDeleteFramebuffers
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers);
+GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
+#define glGenFramebuffers glad_glGenFramebuffers
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);
+GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
+#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
+#define glFramebufferTexture1D glad_glFramebufferTexture1D
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
+#define glFramebufferTexture2D glad_glFramebufferTexture2D
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
+#define glFramebufferTexture3D glad_glFramebufferTexture3D
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
+#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
+GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
+#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target);
+GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
+#define glGenerateMipmap glad_glGenerateMipmap
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
+#define glBlitFramebuffer glad_glBlitFramebuffer
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
+#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
+#define glFramebufferTextureLayer glad_glFramebufferTextureLayer
+typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
+#define glMapBufferRange glad_glMapBufferRange
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);
+GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
+#define glFlushMappedBufferRange glad_glFlushMappedBufferRange
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array);
+GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
+#define glBindVertexArray glad_glBindVertexArray
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays);
+GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
+#define glDeleteVertexArrays glad_glDeleteVertexArrays
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays);
+GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
+#define glGenVertexArrays glad_glGenVertexArrays
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array);
+GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
+#define glIsVertexArray glad_glIsVertexArray
+#endif
+#ifndef GL_VERSION_3_1
+#define GL_VERSION_3_1 1
+GLAPI int GLAD_GL_VERSION_3_1;
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
+#define glDrawArraysInstanced glad_glDrawArraysInstanced
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
+#define glDrawElementsInstanced glad_glDrawElementsInstanced
+typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer;
+#define glTexBuffer glad_glTexBuffer
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);
+GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
+#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex
+typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
+#define glCopyBufferSubData glad_glCopyBufferSubData
+typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
+#define glGetUniformIndices glad_glGetUniformIndices
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
+#define glGetActiveUniformsiv glad_glGetActiveUniformsiv
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
+GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
+#define glGetActiveUniformName glad_glGetActiveUniformName
+typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName);
+GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
+#define glGetUniformBlockIndex glad_glGetUniformBlockIndex
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
+#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
+#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName
+typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
+#define glUniformBlockBinding glad_glUniformBlockBinding
+#endif
+#ifndef GL_VERSION_3_2
+#define GL_VERSION_3_2 1
+GLAPI int GLAD_GL_VERSION_3_2;
+typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
+#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
+#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
+#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
+GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
+#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex
+typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode);
+GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
+#define glProvokingVertex glad_glProvokingVertex
+typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);
+GLAPI PFNGLFENCESYNCPROC glad_glFenceSync;
+#define glFenceSync glad_glFenceSync
+typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync);
+GLAPI PFNGLISSYNCPROC glad_glIsSync;
+#define glIsSync glad_glIsSync
+typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync);
+GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync;
+#define glDeleteSync glad_glDeleteSync
+typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
+#define glClientWaitSync glad_glClientWaitSync
+typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI PFNGLWAITSYNCPROC glad_glWaitSync;
+#define glWaitSync glad_glWaitSync
+typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data);
+GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
+#define glGetInteger64v glad_glGetInteger64v
+typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv;
+#define glGetSynciv glad_glGetSynciv
+typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data);
+GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
+#define glGetInteger64i_v glad_glGetInteger64i_v
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params);
+GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
+#define glGetBufferParameteri64v glad_glGetBufferParameteri64v
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
+#define glFramebufferTexture glad_glFramebufferTexture
+typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
+#define glTexImage2DMultisample glad_glTexImage2DMultisample
+typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
+#define glTexImage3DMultisample glad_glTexImage3DMultisample
+typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val);
+GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
+#define glGetMultisamplefv glad_glGetMultisamplefv
+typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);
+GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
+#define glSampleMaski glad_glSampleMaski
+#endif
+#ifndef GL_VERSION_3_3
+#define GL_VERSION_3_3 1
+GLAPI int GLAD_GL_VERSION_3_3;
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
+#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed
+typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name);
+GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
+#define glGetFragDataIndex glad_glGetFragDataIndex
+typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers);
+GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers;
+#define glGenSamplers glad_glGenSamplers
+typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers);
+GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
+#define glDeleteSamplers glad_glDeleteSamplers
+typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler);
+GLAPI PFNGLISSAMPLERPROC glad_glIsSampler;
+#define glIsSampler glad_glIsSampler
+typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);
+GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler;
+#define glBindSampler glad_glBindSampler
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);
+GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
+#define glSamplerParameteri glad_glSamplerParameteri
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param);
+GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
+#define glSamplerParameteriv glad_glSamplerParameteriv
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);
+GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
+#define glSamplerParameterf glad_glSamplerParameterf
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param);
+GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
+#define glSamplerParameterfv glad_glSamplerParameterfv
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param);
+GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
+#define glSamplerParameterIiv glad_glSamplerParameterIiv
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param);
+GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
+#define glSamplerParameterIuiv glad_glSamplerParameterIuiv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params);
+GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
+#define glGetSamplerParameteriv glad_glGetSamplerParameteriv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params);
+GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
+#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params);
+GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
+#define glGetSamplerParameterfv glad_glGetSamplerParameterfv
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params);
+GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
+#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv
+typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);
+GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
+#define glQueryCounter glad_glQueryCounter
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params);
+GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
+#define glGetQueryObjecti64v glad_glGetQueryObjecti64v
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params);
+GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
+#define glGetQueryObjectui64v glad_glGetQueryObjectui64v
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);
+GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
+#define glVertexAttribDivisor glad_glVertexAttribDivisor
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
+#define glVertexAttribP1ui glad_glVertexAttribP1ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
+#define glVertexAttribP1uiv glad_glVertexAttribP1uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
+#define glVertexAttribP2ui glad_glVertexAttribP2ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
+#define glVertexAttribP2uiv glad_glVertexAttribP2uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
+#define glVertexAttribP3ui glad_glVertexAttribP3ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
+#define glVertexAttribP3uiv glad_glVertexAttribP3uiv
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
+#define glVertexAttribP4ui glad_glVertexAttribP4ui
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
+#define glVertexAttribP4uiv glad_glVertexAttribP4uiv
+typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value);
+GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
+#define glVertexP2ui glad_glVertexP2ui
+typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value);
+GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
+#define glVertexP2uiv glad_glVertexP2uiv
+typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value);
+GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
+#define glVertexP3ui glad_glVertexP3ui
+typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value);
+GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
+#define glVertexP3uiv glad_glVertexP3uiv
+typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value);
+GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
+#define glVertexP4ui glad_glVertexP4ui
+typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value);
+GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
+#define glVertexP4uiv glad_glVertexP4uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
+#define glTexCoordP1ui glad_glTexCoordP1ui
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords);
+GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
+#define glTexCoordP1uiv glad_glTexCoordP1uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
+#define glTexCoordP2ui glad_glTexCoordP2ui
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords);
+GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
+#define glTexCoordP2uiv glad_glTexCoordP2uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
+#define glTexCoordP3ui glad_glTexCoordP3ui
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords);
+GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
+#define glTexCoordP3uiv glad_glTexCoordP3uiv
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
+#define glTexCoordP4ui glad_glTexCoordP4ui
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords);
+GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
+#define glTexCoordP4uiv glad_glTexCoordP4uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
+#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
+GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
+#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
+#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
+GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
+#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
+#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
+GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
+#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords);
+GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
+#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
+GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
+#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv
+typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords);
+GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui;
+#define glNormalP3ui glad_glNormalP3ui
+typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords);
+GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
+#define glNormalP3uiv glad_glNormalP3uiv
+typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color);
+GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui;
+#define glColorP3ui glad_glColorP3ui
+typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color);
+GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
+#define glColorP3uiv glad_glColorP3uiv
+typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color);
+GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui;
+#define glColorP4ui glad_glColorP4ui
+typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color);
+GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
+#define glColorP4uiv glad_glColorP4uiv
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color);
+GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
+#define glSecondaryColorP3ui glad_glSecondaryColorP3ui
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color);
+GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
+#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/d2tk/pugl/examples/glad/khrplatform.h b/subprojects/d2tk/pugl/examples/glad/khrplatform.h
new file mode 100644
index 0000000..5b55ea2
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/glad/khrplatform.h
@@ -0,0 +1,290 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * The master copy of khrplatform.h is maintained in the Khronos EGL
+ * Registry repository at https://github.com/KhronosGroup/EGL-Registry
+ * The last semantic modification to khrplatform.h was at commit ID:
+ * 67a3e0864c2d75ea5287b9f3d2eb74a745936692
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by filing pull requests or issues on
+ * the EGL Registry repository linked above.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
+# define KHRONOS_STATIC 1
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(KHRONOS_STATIC)
+ /* If the preprocessor constant KHRONOS_STATIC is defined, make the
+ * header compatible with static linking. */
+# define KHRONOS_APICALL
+#elif defined(_WIN32)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#elif defined(__ANDROID__)
+# define KHRONOS_APICALL __attribute__((visibility("default")))
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64,
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/subprojects/d2tk/pugl/examples/meson.build b/subprojects/d2tk/pugl/examples/meson.build
new file mode 100644
index 0000000..d455faf
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/meson.build
@@ -0,0 +1,80 @@
+data_dir = get_option('prefix') / get_option('datadir') / 'pugl-0'
+example_args = ['-DPUGL_DATA_DIR="@0@"'.format(data_dir)]
+
+gl_examples = [
+ 'pugl_cxx_demo.cpp',
+ 'pugl_embed_demo.c',
+ 'pugl_print_events.c',
+ 'pugl_shader_demo.c',
+ 'pugl_window_demo.c',
+]
+
+cairo_examples = [
+ 'pugl_cairo_demo.c'
+]
+
+vulkan_examples = [
+ 'pugl_vulkan_cxx_demo.cpp',
+ 'pugl_vulkan_demo.c',
+]
+
+includes = [
+ '.',
+ '..',
+ '../bindings/cxx/include',
+ '../include',
+]
+
+subdir('shaders')
+
+# Build GL examples
+if opengl_dep.found()
+ foreach example : gl_examples
+ source = [example]
+ target = example.split('.')[0]
+ dependencies = [gl_backend_dep]
+
+ if target == 'pugl_shader_demo'
+ source += ['file_utils.c', 'glad/glad.c']
+ dependencies += [dl_dep]
+ elif target == 'pugl_print_events'
+ dependencies += [stub_backend_dep]
+ endif
+
+ executable(target, source,
+ include_directories: include_directories(includes),
+ c_args: example_args,
+ cpp_args: example_args,
+ dependencies: dependencies)
+ endforeach
+endif
+
+# Build Cairo examples
+if cairo_dep.found()
+ foreach example : cairo_examples
+ target = example.split('.')[0]
+ executable(target, example,
+ include_directories: include_directories(includes),
+ c_args: example_args,
+ dependencies: [pugl_dep, cairo_backend_dep])
+ endforeach
+endif
+
+# Build Vulkan examples
+if vulkan_dep.found()
+ foreach example : vulkan_examples
+ source = [example]
+ target = example.split('.')[0]
+ dependencies = [dl_dep, vulkan_backend_dep]
+
+ if target == 'pugl_vulkan_cxx_demo'
+ source += ['file_utils.c']
+ endif
+
+ executable(target, source,
+ include_directories: include_directories(includes),
+ c_args: example_args,
+ cpp_args: example_args,
+ dependencies: dependencies)
+ endforeach
+endif
diff --git a/subprojects/d2tk/pugl/examples/pugl_cairo_demo.c b/subprojects/d2tk/pugl/examples/pugl_cairo_demo.c
new file mode 100644
index 0000000..67bc13c
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_cairo_demo.c
@@ -0,0 +1,261 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/cairo.h"
+#include "pugl/pugl.h"
+
+#include <cairo.h>
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+ PuglWorld* world;
+ PuglTestOptions opts;
+ unsigned framesDrawn;
+ int quit;
+ bool entered;
+ bool mouseDown;
+} PuglTestApp;
+
+typedef struct {
+ int x;
+ int y;
+ int w;
+ int h;
+ const char* label;
+} Button;
+
+static const Button buttons[] = {{128, 128, 64, 64, "1"},
+ {384, 128, 64, 64, "2"},
+ {128, 384, 64, 64, "3"},
+ {384, 384, 64, 64, "4"},
+ {0, 0, 0, 0, NULL}};
+
+static void
+roundedBox(cairo_t* cr, double x, double y, double w, double h)
+{
+ static const double radius = 10;
+ static const double degrees = 3.14159265 / 180.0;
+
+ cairo_new_sub_path(cr);
+ cairo_arc(cr, x + w - radius, y + radius, radius, -90 * degrees, 0 * degrees);
+
+ cairo_arc(
+ cr, x + w - radius, y + h - radius, radius, 0 * degrees, 90 * degrees);
+
+ cairo_arc(
+ cr, x + radius, y + h - radius, radius, 90 * degrees, 180 * degrees);
+
+ cairo_arc(cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
+ cairo_close_path(cr);
+}
+
+static void
+buttonDraw(PuglTestApp* app, cairo_t* cr, const Button* but, const double time)
+{
+ cairo_save(cr);
+ cairo_translate(cr, but->x, but->y);
+ cairo_rotate(cr, sin(time) * 3.141592);
+
+ // Draw base
+ if (app->mouseDown) {
+ cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1);
+ } else {
+ cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1);
+ }
+ roundedBox(cr, 0, 0, but->w, but->h);
+ cairo_fill_preserve(cr);
+
+ // Draw border
+ cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1);
+ cairo_set_line_width(cr, 4.0);
+ cairo_stroke(cr);
+
+ // Draw label
+ cairo_text_extents_t extents;
+ cairo_set_font_size(cr, 32.0);
+ cairo_text_extents(cr, but->label, &extents);
+ cairo_move_to(cr,
+ (but->w / 2.0) - extents.width / 2,
+ (but->h / 2.0) + extents.height / 2);
+ cairo_set_source_rgba(cr, 0, 0, 0, 1);
+ cairo_show_text(cr, but->label);
+
+ cairo_restore(cr);
+}
+
+static void
+postButtonRedisplay(PuglView* view)
+{
+ const PuglRect frame = puglGetFrame(view);
+ const double width = frame.width;
+ const double height = frame.height;
+ const double scaleX = (width - (512 / width)) / 512.0;
+ const double scaleY = (height - (512 / height)) / 512.0;
+
+ for (const Button* b = buttons; b->label; ++b) {
+ const double span = sqrt(b->w * b->w + b->h * b->h);
+ const PuglRect rect = {(b->x - span) * scaleX,
+ (b->y - span) * scaleY,
+ span * 2.0 * scaleX,
+ span * 2.0 * scaleY};
+
+ puglPostRedisplayRect(view, rect);
+ }
+}
+
+static void
+onDisplay(PuglTestApp* app, PuglView* view, const PuglEventExpose* event)
+{
+ cairo_t* cr = (cairo_t*)puglGetContext(view);
+
+ cairo_rectangle(cr, event->x, event->y, event->width, event->height);
+ cairo_clip_preserve(cr);
+
+ // Draw background
+ const PuglRect frame = puglGetFrame(view);
+ const double width = frame.width;
+ const double height = frame.height;
+ if (app->entered) {
+ cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
+ } else {
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ }
+ cairo_fill(cr);
+
+ // Scale to view size
+ const double scaleX = (width - (512 / width)) / 512.0;
+ const double scaleY = (height - (512 / height)) / 512.0;
+ cairo_scale(cr, scaleX, scaleY);
+
+ // Draw button
+ for (const Button* b = buttons; b->label; ++b) {
+ buttonDraw(
+ app, cr, b, app->opts.continuous ? puglGetTime(app->world) : 0.0);
+ }
+
+ ++app->framesDrawn;
+}
+
+static void
+onClose(PuglView* view)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ app->quit = 1;
+}
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ printEvent(event, "Event: ", app->opts.verbose);
+
+ switch (event->type) {
+ case PUGL_KEY_PRESS:
+ if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
+ app->quit = 1;
+ }
+ break;
+ case PUGL_BUTTON_PRESS:
+ app->mouseDown = true;
+ postButtonRedisplay(view);
+ break;
+ case PUGL_BUTTON_RELEASE:
+ app->mouseDown = false;
+ postButtonRedisplay(view);
+ break;
+ case PUGL_POINTER_IN:
+ app->entered = true;
+ puglPostRedisplay(view);
+ break;
+ case PUGL_POINTER_OUT:
+ app->entered = false;
+ puglPostRedisplay(view);
+ break;
+ case PUGL_UPDATE:
+ if (app->opts.continuous) {
+ puglPostRedisplay(view);
+ }
+ break;
+ case PUGL_EXPOSE:
+ onDisplay(app, view, &event->expose);
+ break;
+ case PUGL_CLOSE:
+ onClose(view);
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTestApp app;
+ memset(&app, 0, sizeof(app));
+
+ app.opts = puglParseTestOptions(&argc, &argv);
+ if (app.opts.help) {
+ puglPrintTestUsage("pugl_test", "");
+ return 1;
+ }
+
+ app.world = puglNewWorld(PUGL_PROGRAM, 0);
+ puglSetClassName(app.world, "PuglCairoTest");
+
+ PuglView* view = puglNewView(app.world);
+
+ puglSetWindowTitle(view, "Pugl Cairo Demo");
+ puglSetDefaultSize(view, 512, 512);
+ puglSetMinSize(view, 256, 256);
+ puglSetMaxSize(view, 2048, 2048);
+ puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable);
+ puglSetHandle(view, &app);
+ puglSetBackend(view, puglCairoBackend());
+ puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat);
+ puglSetEventFunc(view, onEvent);
+
+ PuglStatus st = puglRealize(view);
+ if (st) {
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ puglShow(view);
+
+ PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
+ const double timeout = app.opts.continuous ? (1 / 60.0) : -1.0;
+ while (!app.quit) {
+ puglUpdate(app.world, timeout);
+
+ if (app.opts.continuous) {
+ puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn);
+ }
+ }
+
+ puglFreeView(view);
+ puglFreeWorld(app.world);
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_cursor_demo.c b/subprojects/d2tk/pugl/examples/pugl_cursor_demo.c
new file mode 100644
index 0000000..97e3b9f
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_cursor_demo.c
@@ -0,0 +1,169 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "test/test_utils.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+
+#include <stdbool.h>
+
+static const int N_CURSORS = 7;
+static const int N_ROWS = 2;
+static const int N_COLS = 4;
+
+typedef struct {
+ PuglWorld* world;
+ PuglTestOptions opts;
+ bool quit;
+} PuglTestApp;
+
+static void
+onConfigure(const double width, const double height)
+{
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glViewport(0, 0, (int)width, (int)height);
+}
+
+static void
+onExpose(void)
+{
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glColor3f(0.6f, 0.6f, 0.6f);
+
+ for (int row = 1; row < N_ROWS; ++row) {
+ const float y = (float)row * (2.0f / (float)N_ROWS) - 1.0f;
+ glBegin(GL_LINES);
+ glVertex2f(-1.0f, y);
+ glVertex2f(1.0f, y);
+ glEnd();
+ }
+
+ for (int col = 1; col < N_COLS; ++col) {
+ const float x = (float)col * (2.0f / (float)N_COLS) - 1.0f;
+ glBegin(GL_LINES);
+ glVertex2f(x, -1.0f);
+ glVertex2f(x, 1.0f);
+ glEnd();
+ }
+}
+
+static void
+onMotion(PuglView* view, double x, double y)
+{
+ const PuglRect frame = puglGetFrame(view);
+ int row = (int)(y * N_ROWS / frame.height);
+ int col = (int)(x * N_COLS / frame.width);
+
+ row = (row < 0) ? 0 : (row >= N_ROWS) ? (N_ROWS - 1) : row;
+ col = (col < 0) ? 0 : (col >= N_COLS) ? (N_COLS - 1) : col;
+
+ const PuglCursor cursor = (PuglCursor)((row * N_COLS + col) % N_CURSORS);
+ puglSetCursor(view, cursor);
+}
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ printEvent(event, "Event: ", app->opts.verbose);
+
+ switch (event->type) {
+ case PUGL_CONFIGURE:
+ onConfigure(event->configure.width, event->configure.height);
+ break;
+ case PUGL_KEY_PRESS:
+ if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
+ app->quit = 1;
+ }
+ break;
+ case PUGL_MOTION:
+ onMotion(view, event->motion.x, event->motion.y);
+ break;
+ case PUGL_EXPOSE:
+ onExpose();
+ break;
+ case PUGL_POINTER_OUT:
+ puglSetCursor(view, PUGL_CURSOR_ARROW);
+ break;
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTestApp app = {0};
+
+ app.opts = puglParseTestOptions(&argc, &argv);
+ if (app.opts.help) {
+ puglPrintTestUsage(argv[0], "");
+ return 1;
+ }
+
+ app.world = puglNewWorld(PUGL_PROGRAM, 0);
+
+ puglSetWorldHandle(app.world, &app);
+ puglSetClassName(app.world, "Pugl Test");
+
+ PuglView* view = puglNewView(app.world);
+
+ puglSetWindowTitle(view, "Pugl Window Demo");
+ puglSetDefaultSize(view, 512, 256);
+ puglSetMinSize(view, 128, 64);
+ puglSetMaxSize(view, 512, 256);
+ puglSetBackend(view, puglGlBackend());
+
+ puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking);
+ puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable);
+ puglSetViewHint(view, PUGL_SAMPLES, app.opts.samples);
+ puglSetViewHint(view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer);
+ puglSetViewHint(view, PUGL_SWAP_INTERVAL, app.opts.sync);
+ puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat);
+ puglSetHandle(view, &app);
+ puglSetEventFunc(view, onEvent);
+
+ const PuglStatus st = puglRealize(view);
+ if (st) {
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ puglShow(view);
+
+ while (!app.quit) {
+ puglUpdate(app.world, -1.0);
+ }
+
+ puglFreeView(view);
+ puglFreeWorld(app.world);
+
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_cxx_demo.cpp b/subprojects/d2tk/pugl/examples/pugl_cxx_demo.cpp
new file mode 100644
index 0000000..d663a3f
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_cxx_demo.cpp
@@ -0,0 +1,148 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "cube_view.h"
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/gl.hpp"
+#include "pugl/pugl.h"
+#include "pugl/pugl.hpp"
+
+#include <cmath>
+
+class CubeView : public pugl::View
+{
+public:
+ explicit CubeView(pugl::World& world)
+ : pugl::View{world}
+ {
+ setEventHandler(*this);
+ }
+
+ template<PuglEventType t, class Base>
+ pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept
+ {
+ return pugl::Status::success;
+ }
+
+ static pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept;
+ pugl::Status onEvent(const pugl::UpdateEvent& event) noexcept;
+ pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept;
+ pugl::Status onEvent(const pugl::KeyPressEvent& event) noexcept;
+ pugl::Status onEvent(const pugl::CloseEvent& event) noexcept;
+
+ bool quit() const { return _quit; }
+
+private:
+ double _xAngle{0.0};
+ double _yAngle{0.0};
+ double _lastDrawTime{0.0};
+ bool _quit{false};
+};
+
+pugl::Status
+CubeView::onEvent(const pugl::ConfigureEvent& event) noexcept
+{
+ reshapeCube(static_cast<float>(event.width),
+ static_cast<float>(event.height));
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+CubeView::onEvent(const pugl::UpdateEvent&) noexcept
+{
+ return postRedisplay();
+}
+
+pugl::Status
+CubeView::onEvent(const pugl::ExposeEvent&) noexcept
+{
+ const double thisTime = world().time();
+ const double dTime = thisTime - _lastDrawTime;
+ const double dAngle = dTime * 100.0;
+
+ _xAngle = fmod(_xAngle + dAngle, 360.0);
+ _yAngle = fmod(_yAngle + dAngle, 360.0);
+ displayCube(cobj(),
+ 8.0f,
+ static_cast<float>(_xAngle),
+ static_cast<float>(_yAngle),
+ false);
+
+ _lastDrawTime = thisTime;
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+CubeView::onEvent(const pugl::KeyPressEvent& event) noexcept
+{
+ if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') {
+ _quit = true;
+ }
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+CubeView::onEvent(const pugl::CloseEvent&) noexcept
+{
+ _quit = true;
+
+ return pugl::Status::success;
+}
+
+int
+main(int argc, char** argv)
+{
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage("pugl_cxx_demo", "");
+ return 1;
+ }
+
+ pugl::World world{pugl::WorldType::program};
+ CubeView view{world};
+ PuglFpsPrinter fpsPrinter{};
+
+ world.setClassName("PuglCppTest");
+
+ view.setWindowTitle("Pugl C++ Test");
+ view.setDefaultSize(512, 512);
+ view.setMinSize(64, 64);
+ view.setMaxSize(256, 256);
+ view.setAspectRatio(1, 1, 16, 9);
+ view.setBackend(pugl::glBackend());
+ view.setHint(pugl::ViewHint::resizable, opts.resizable);
+ view.setHint(pugl::ViewHint::samples, opts.samples);
+ view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer);
+ view.setHint(pugl::ViewHint::swapInterval, opts.sync);
+ view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat);
+ view.realize();
+ view.show();
+
+ unsigned framesDrawn = 0;
+ while (!view.quit()) {
+ world.update(0.0);
+
+ ++framesDrawn;
+ puglPrintFps(world.cobj(), &fpsPrinter, &framesDrawn);
+ }
+
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_embed_demo.c b/subprojects/d2tk/pugl/examples/pugl_embed_demo.c
new file mode 100644
index 0000000..0e12ddb
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_embed_demo.c
@@ -0,0 +1,354 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "cube_view.h"
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+static const int borderWidth = 64;
+static const uintptr_t reverseTimerId = 1u;
+
+typedef struct {
+ PuglWorld* world;
+ PuglView* parent;
+ PuglView* child;
+ double xAngle;
+ double yAngle;
+ double lastMouseX;
+ double lastMouseY;
+ double lastDrawTime;
+ float dist;
+ int quit;
+ bool continuous;
+ bool mouseEntered;
+ bool verbose;
+ bool reversing;
+} PuglTestApp;
+
+// clang-format off
+static const float backgroundVertices[] = {
+ -1.0f, 1.0f, -1.0f, // Top left
+ 1.0f, 1.0f, -1.0f, // Top right
+ -1.0f, -1.0f, -1.0f, // Bottom left
+ 1.0f, -1.0f, -1.0f, // Bottom right
+};
+// clang-format on
+
+static PuglRect
+getChildFrame(const PuglRect parentFrame)
+{
+ const PuglRect childFrame = {borderWidth,
+ borderWidth,
+ parentFrame.width - 2 * borderWidth,
+ parentFrame.height - 2 * borderWidth};
+
+ return childFrame;
+}
+
+static void
+onDisplay(PuglView* view)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ const double thisTime = puglGetTime(app->world);
+ if (app->continuous) {
+ const double dTime =
+ (thisTime - app->lastDrawTime) * (app->reversing ? -1.0 : 1.0);
+
+ app->xAngle = fmod(app->xAngle + dTime * 100.0, 360.0);
+ app->yAngle = fmod(app->yAngle + dTime * 100.0, 360.0);
+ }
+
+ displayCube(
+ view, app->dist, (float)app->xAngle, (float)app->yAngle, app->mouseEntered);
+
+ app->lastDrawTime = thisTime;
+}
+
+static void
+swapFocus(PuglTestApp* app)
+{
+ if (puglHasFocus(app->parent)) {
+ puglGrabFocus(app->child);
+ } else {
+ puglGrabFocus(app->parent);
+ }
+
+ if (!app->continuous) {
+ puglPostRedisplay(app->parent);
+ puglPostRedisplay(app->child);
+ }
+}
+
+static void
+onKeyPress(PuglView* view, const PuglEventKey* event, const char* prefix)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+ PuglRect frame = puglGetFrame(view);
+
+ if (event->key == '\t') {
+ swapFocus(app);
+ } else if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) {
+ app->quit = 1;
+ } else if (event->state & PUGL_MOD_CTRL && event->key == 'c') {
+ puglSetClipboard(view, NULL, "Pugl test", strlen("Pugl test") + 1);
+ fprintf(stderr, "%sCopy \"Pugl test\"\n", prefix);
+ } else if (event->state & PUGL_MOD_CTRL && event->key == 'v') {
+ const char* type = NULL;
+ size_t len = 0;
+ const char* text = (const char*)puglGetClipboard(view, &type, &len);
+ fprintf(stderr, "%sPaste \"%s\"\n", prefix, text);
+ } else if (event->state & PUGL_MOD_SHIFT) {
+ if (event->key == PUGL_KEY_UP) {
+ frame.height += 10;
+ } else if (event->key == PUGL_KEY_DOWN) {
+ frame.height -= 10;
+ } else if (event->key == PUGL_KEY_LEFT) {
+ frame.width -= 10;
+ } else if (event->key == PUGL_KEY_RIGHT) {
+ frame.width += 10;
+ } else {
+ return;
+ }
+ puglSetFrame(view, frame);
+ } else {
+ if (event->key == PUGL_KEY_UP) {
+ frame.y -= 10;
+ } else if (event->key == PUGL_KEY_DOWN) {
+ frame.y += 10;
+ } else if (event->key == PUGL_KEY_LEFT) {
+ frame.x -= 10;
+ } else if (event->key == PUGL_KEY_RIGHT) {
+ frame.x += 10;
+ } else {
+ return;
+ }
+ puglSetFrame(view, frame);
+ }
+}
+
+static PuglStatus
+onParentEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+ const PuglRect parentFrame = puglGetFrame(view);
+
+ printEvent(event, "Parent: ", app->verbose);
+
+ switch (event->type) {
+ case PUGL_CONFIGURE:
+ reshapeCube((float)event->configure.width, (float)event->configure.height);
+
+ puglSetFrame(app->child, getChildFrame(parentFrame));
+ break;
+ case PUGL_UPDATE:
+ if (app->continuous) {
+ puglPostRedisplay(view);
+ }
+ break;
+ case PUGL_EXPOSE:
+ if (puglHasFocus(app->parent)) {
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, backgroundVertices);
+ glColorPointer(3, GL_FLOAT, 0, backgroundVertices);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ } else {
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+ break;
+ case PUGL_KEY_PRESS:
+ onKeyPress(view, &event->key, "Parent: ");
+ break;
+ case PUGL_MOTION:
+ break;
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ printEvent(event, "Child: ", app->verbose);
+
+ switch (event->type) {
+ case PUGL_CONFIGURE:
+ reshapeCube((float)event->configure.width, (float)event->configure.height);
+ break;
+ case PUGL_UPDATE:
+ if (app->continuous) {
+ puglPostRedisplay(view);
+ }
+ break;
+ case PUGL_EXPOSE:
+ onDisplay(view);
+ break;
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ case PUGL_KEY_PRESS:
+ onKeyPress(view, &event->key, "Child: ");
+ break;
+ case PUGL_MOTION:
+ app->xAngle -= event->motion.x - app->lastMouseX;
+ app->yAngle += event->motion.y - app->lastMouseY;
+ app->lastMouseX = event->motion.x;
+ app->lastMouseY = event->motion.y;
+ if (!app->continuous) {
+ puglPostRedisplay(view);
+ puglPostRedisplay(app->parent);
+ }
+ break;
+ case PUGL_SCROLL:
+ app->dist = fmaxf(10.0f, app->dist + (float)event->scroll.dy);
+ if (!app->continuous) {
+ puglPostRedisplay(view);
+ }
+ break;
+ case PUGL_POINTER_IN:
+ app->mouseEntered = true;
+ break;
+ case PUGL_POINTER_OUT:
+ app->mouseEntered = false;
+ break;
+ case PUGL_TIMER:
+ app->reversing = !app->reversing;
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTestApp app = {0};
+
+ app.dist = 10;
+
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage("pugl_test", "");
+ return 1;
+ }
+
+ app.continuous = opts.continuous;
+ app.verbose = opts.verbose;
+
+ app.world = puglNewWorld(PUGL_PROGRAM, 0);
+ app.parent = puglNewView(app.world);
+ app.child = puglNewView(app.world);
+
+ puglSetClassName(app.world, "Pugl Test");
+
+ const PuglRect parentFrame = {0, 0, 512, 512};
+ puglSetDefaultSize(app.parent, 512, 512);
+ puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3);
+ puglSetMaxSize(app.parent, 1024, 1024);
+ puglSetAspectRatio(app.parent, 1, 1, 16, 9);
+ puglSetBackend(app.parent, puglGlBackend());
+
+ puglSetViewHint(app.parent, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking);
+ puglSetViewHint(app.parent, PUGL_RESIZABLE, opts.resizable);
+ puglSetViewHint(app.parent, PUGL_SAMPLES, opts.samples);
+ puglSetViewHint(app.parent, PUGL_DOUBLE_BUFFER, opts.doubleBuffer);
+ puglSetViewHint(app.parent, PUGL_SWAP_INTERVAL, opts.sync);
+ puglSetViewHint(app.parent, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat);
+ puglSetHandle(app.parent, &app);
+ puglSetEventFunc(app.parent, onParentEvent);
+
+ PuglStatus st = PUGL_SUCCESS;
+ const uint8_t title[] = {
+ 'P', 'u', 'g', 'l', ' ', 'P', 'r', 0xC3, 0xBC, 'f', 'u', 'n', 'g', 0};
+
+ puglSetWindowTitle(app.parent, (const char*)title);
+
+ if ((st = puglRealize(app.parent))) {
+ return logError("Failed to create parent window (%s)\n", puglStrerror(st));
+ }
+
+ puglSetFrame(app.child, getChildFrame(parentFrame));
+ puglSetParentWindow(app.child, puglGetNativeWindow(app.parent));
+
+ puglSetViewHint(app.child, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking);
+ puglSetViewHint(app.child, PUGL_SAMPLES, opts.samples);
+ puglSetViewHint(app.child, PUGL_DOUBLE_BUFFER, opts.doubleBuffer);
+ puglSetViewHint(app.child, PUGL_SWAP_INTERVAL, opts.sync);
+ puglSetBackend(app.child, puglGlBackend());
+ puglSetViewHint(app.child, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat);
+ puglSetHandle(app.child, &app);
+ puglSetEventFunc(app.child, onEvent);
+
+ if ((st = puglRealize(app.child))) {
+ return logError("Failed to create child window (%s)\n", puglStrerror(st));
+ }
+
+ puglShow(app.parent);
+ puglShow(app.child);
+
+ puglStartTimer(app.child, reverseTimerId, 3.6);
+
+ PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
+ unsigned framesDrawn = 0;
+ bool requestedAttention = false;
+ while (!app.quit) {
+ const double thisTime = puglGetTime(app.world);
+
+ puglUpdate(app.world, app.continuous ? 0.0 : -1.0);
+ ++framesDrawn;
+
+ if (!requestedAttention && thisTime > 5.0) {
+ puglRequestAttention(app.parent);
+ requestedAttention = true;
+ }
+
+ if (app.continuous) {
+ puglPrintFps(app.world, &fpsPrinter, &framesDrawn);
+ }
+ }
+
+ puglFreeView(app.child);
+ puglFreeView(app.parent);
+ puglFreeWorld(app.world);
+
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_print_events.c b/subprojects/d2tk/pugl/examples/pugl_print_events.c
new file mode 100644
index 0000000..dfa217e
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_print_events.c
@@ -0,0 +1,79 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "test/test_utils.h"
+
+#include "pugl/pugl.h"
+#include "pugl/stub.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef struct {
+ PuglWorld* world;
+ PuglView* view;
+ int quit;
+} PuglPrintEventsApp;
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglPrintEventsApp* app = (PuglPrintEventsApp*)puglGetHandle(view);
+
+ printEvent(event, "Event: ", true);
+
+ switch (event->type) {
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+int
+main(void)
+{
+ PuglPrintEventsApp app = {NULL, NULL, 0};
+
+ app.world = puglNewWorld(PUGL_PROGRAM, 0);
+ app.view = puglNewView(app.world);
+
+ puglSetClassName(app.world, "Pugl Print Events");
+ puglSetWindowTitle(app.view, "Pugl Event Printer");
+ puglSetDefaultSize(app.view, 512, 512);
+ puglSetBackend(app.view, puglStubBackend());
+ puglSetHandle(app.view, &app);
+ puglSetEventFunc(app.view, onEvent);
+
+ PuglStatus st = puglRealize(app.view);
+ if (st) {
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ puglShow(app.view);
+
+ while (!app.quit) {
+ puglUpdate(app.world, -1.0);
+ }
+
+ puglFreeView(app.view);
+ puglFreeWorld(app.world);
+
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_shader_demo.c b/subprojects/d2tk/pugl/examples/pugl_shader_demo.c
new file mode 100644
index 0000000..aa5c38e
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_shader_demo.c
@@ -0,0 +1,470 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ An example of drawing with OpenGL 3/4.
+
+ This is an example of using OpenGL for pixel-perfect 2D drawing. It uses
+ pixel coordinates for positions and sizes so that things work roughly like a
+ typical 2D graphics API.
+
+ The program draws a bunch of rectangles with borders, using instancing.
+ Each rectangle has origin, size, and fill color attributes, which are shared
+ for all four vertices. On each frame, a single buffer with all the
+ rectangle data is sent to the GPU, and everything is drawn with a single
+ draw call.
+
+ This is not particularly realistic or optimal, but serves as a decent rough
+ benchmark for how much simple geometry you can draw. The number of
+ rectangles can be given on the command line. For reference, it begins to
+ struggle to maintain 60 FPS on my machine (1950x + Vega64) with more than
+ about 100000 rectangles.
+*/
+
+#include "demo_utils.h"
+#include "file_utils.h"
+#include "rects.h"
+#include "shader_utils.h"
+#include "test/test_utils.h"
+
+#include "glad/glad.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+
+#include <math.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const int defaultWidth = 512;
+static const int defaultHeight = 512;
+static const uintptr_t resizeTimerId = 1u;
+
+typedef struct {
+ mat4 projection;
+} RectUniforms;
+
+typedef struct {
+ const char* programPath;
+ PuglWorld* world;
+ PuglView* view;
+ PuglTestOptions opts;
+ size_t numRects;
+ Rect* rects;
+ Program drawRect;
+ GLuint vao;
+ GLuint vbo;
+ GLuint instanceVbo;
+ GLuint ibo;
+ double lastDrawDuration;
+ double lastFrameEndTime;
+ unsigned framesDrawn;
+ int glMajorVersion;
+ int glMinorVersion;
+ int quit;
+} PuglTestApp;
+
+static PuglStatus
+setupGl(PuglTestApp* app);
+
+static void
+teardownGl(PuglTestApp* app);
+
+static void
+onConfigure(PuglView* view, double width, double height)
+{
+ (void)view;
+
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glViewport(0, 0, (int)width, (int)height);
+}
+
+static void
+onExpose(PuglView* view)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+ const PuglRect frame = puglGetFrame(view);
+ const float width = (float)frame.width;
+ const float height = (float)frame.height;
+ const double time = puglGetTime(puglGetWorld(view));
+
+ // Construct projection matrix for 2D window surface (in pixels)
+ mat4 proj;
+ mat4Ortho(
+ proj, 0.0f, (float)frame.width, 0.0f, (float)frame.height, -1.0f, 1.0f);
+
+ // Clear and bind everything that is the same for every rect
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUseProgram(app->drawRect.program);
+ glBindVertexArray(app->vao);
+
+ for (size_t i = 0; i < app->numRects; ++i) {
+ moveRect(&app->rects[i], i, app->numRects, width, height, time);
+ }
+
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(proj), &proj, GL_STREAM_DRAW);
+
+ glBufferSubData(
+ GL_ARRAY_BUFFER, 0, (GLsizeiptr)(app->numRects * sizeof(Rect)), app->rects);
+
+ glDrawElementsInstanced(
+ GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL, (GLsizei)(app->numRects * 4));
+
+ ++app->framesDrawn;
+
+ app->lastFrameEndTime = puglGetTime(puglGetWorld(view));
+ app->lastDrawDuration = app->lastFrameEndTime - time;
+}
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ printEvent(event, "Event: ", app->opts.verbose);
+
+ switch (event->type) {
+ case PUGL_CREATE:
+ setupGl(app);
+ break;
+ case PUGL_DESTROY:
+ teardownGl(app);
+ break;
+ case PUGL_CONFIGURE:
+ onConfigure(view, event->configure.width, event->configure.height);
+ break;
+ case PUGL_UPDATE:
+ puglPostRedisplay(view);
+ break;
+ case PUGL_EXPOSE:
+ onExpose(view);
+ break;
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ case PUGL_LOOP_ENTER:
+ puglStartTimer(view,
+ resizeTimerId,
+ 1.0 / (double)puglGetViewHint(view, PUGL_REFRESH_RATE));
+ break;
+ case PUGL_LOOP_LEAVE:
+ puglStopTimer(view, resizeTimerId);
+ break;
+ case PUGL_KEY_PRESS:
+ if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
+ app->quit = 1;
+ }
+ break;
+ case PUGL_TIMER:
+ if (event->timer.id == resizeTimerId) {
+ puglPostRedisplay(view);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static Rect*
+makeRects(const size_t numRects)
+{
+ Rect* rects = (Rect*)calloc(numRects, sizeof(Rect));
+ for (size_t i = 0; i < numRects; ++i) {
+ rects[i] = makeRect(i, (float)defaultWidth);
+ }
+
+ return rects;
+}
+
+static char*
+loadShader(const char* const programPath, const char* const name)
+{
+ char* const path = resourcePath(programPath, name);
+ fprintf(stderr, "Loading shader %s\n", path);
+
+ FILE* const file = fopen(path, "r");
+ if (!file) {
+ logError("Failed to open '%s'\n", path);
+ return NULL;
+ }
+
+ free(path);
+ fseek(file, 0, SEEK_END);
+ const size_t fileSize = (size_t)ftell(file);
+
+ fseek(file, 0, SEEK_SET);
+ char* source = (char*)calloc(1, fileSize + 1u);
+
+ fread(source, 1, fileSize, file);
+ fclose(file);
+
+ return source;
+}
+
+static int
+parseOptions(PuglTestApp* app, int argc, char** argv)
+{
+ char* endptr = NULL;
+
+ // Parse command line options
+ app->numRects = 1024;
+ app->opts = puglParseTestOptions(&argc, &argv);
+ if (app->opts.help) {
+ return 1;
+ }
+
+ // Parse number of rectangles argument, if given
+ if (argc >= 1) {
+ app->numRects = (size_t)strtol(argv[0], &endptr, 10);
+ if (endptr != argv[0] + strlen(argv[0])) {
+ logError("Invalid number of rectangles: %s\n", argv[0]);
+ return 1;
+ }
+ }
+
+ // Parse OpenGL major version argument, if given
+ if (argc >= 2) {
+ app->glMajorVersion = (int)strtol(argv[1], &endptr, 10);
+ if (endptr != argv[1] + strlen(argv[1])) {
+ logError("Invalid GL major version: %s\n", argv[1]);
+ return 1;
+ }
+
+ if (app->glMajorVersion == 4) {
+ app->glMinorVersion = 2;
+ } else if (app->glMajorVersion != 3) {
+ logError("Unsupported GL major version %d\n", app->glMajorVersion);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+setupPugl(PuglTestApp* app)
+{
+ // Create world, view, and rect data
+ app->world = puglNewWorld(PUGL_PROGRAM, 0);
+ app->view = puglNewView(app->world);
+ app->rects = makeRects(app->numRects);
+
+ // Set up world and view
+ puglSetClassName(app->world, "PuglGL3Demo");
+ puglSetWindowTitle(app->view, "Pugl OpenGL 3");
+ puglSetDefaultSize(app->view, defaultWidth, defaultHeight);
+ puglSetMinSize(app->view, defaultWidth / 4, defaultHeight / 4);
+ puglSetMaxSize(app->view, defaultWidth * 4, defaultHeight * 4);
+ puglSetAspectRatio(app->view, 1, 1, 16, 9);
+ puglSetBackend(app->view, puglGlBackend());
+ puglSetViewHint(app->view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
+ puglSetViewHint(app->view, PUGL_USE_DEBUG_CONTEXT, app->opts.errorChecking);
+ puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MAJOR, app->glMajorVersion);
+ puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MINOR, app->glMinorVersion);
+ puglSetViewHint(app->view, PUGL_RESIZABLE, app->opts.resizable);
+ puglSetViewHint(app->view, PUGL_SAMPLES, app->opts.samples);
+ puglSetViewHint(app->view, PUGL_DOUBLE_BUFFER, app->opts.doubleBuffer);
+ puglSetViewHint(app->view, PUGL_SWAP_INTERVAL, app->opts.sync);
+ puglSetViewHint(app->view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE);
+ puglSetHandle(app->view, app);
+ puglSetEventFunc(app->view, onEvent);
+}
+
+static PuglStatus
+setupGl(PuglTestApp* app)
+{
+ // Load GL functions via GLAD
+ if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) {
+ logError("Failed to load GL\n");
+ return PUGL_FAILURE;
+ }
+
+ const char* const headerFile =
+ (app->glMajorVersion == 3 ? "shaders/header_330.glsl"
+ : "shaders/header_420.glsl");
+
+ // Load shader sources
+ char* const headerSource = loadShader(app->programPath, headerFile);
+
+ char* const vertexSource = loadShader(app->programPath, "shaders/rect.vert");
+
+ char* const fragmentSource =
+ loadShader(app->programPath, "shaders/rect.frag");
+
+ if (!vertexSource || !fragmentSource) {
+ logError("Failed to load shader sources\n");
+ return PUGL_FAILURE;
+ }
+
+ // Compile rectangle shaders and program
+ app->drawRect = compileProgram(headerSource, vertexSource, fragmentSource);
+ free(fragmentSource);
+ free(vertexSource);
+ free(headerSource);
+ if (!app->drawRect.program) {
+ return PUGL_FAILURE;
+ }
+
+ // Get location of rectangle shader uniform block
+ const GLuint globalsIndex =
+ glGetUniformBlockIndex(app->drawRect.program, "UniformBufferObject");
+
+ // Generate/bind a uniform buffer for setting rectangle properties
+ GLuint uboHandle = 0;
+ glGenBuffers(1, &uboHandle);
+ glBindBuffer(GL_UNIFORM_BUFFER, uboHandle);
+ glBindBufferBase(GL_UNIFORM_BUFFER, globalsIndex, uboHandle);
+
+ // Generate/bind a VAO to track state
+ glGenVertexArrays(1, &app->vao);
+ glBindVertexArray(app->vao);
+
+ // Generate/bind a VBO to store vertex position data
+ glGenBuffers(1, &app->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, app->vbo);
+ glBufferData(
+ GL_ARRAY_BUFFER, sizeof(rectVertices), rectVertices, GL_STATIC_DRAW);
+
+ // Attribute 0 is position, 2 floats from the VBO
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL);
+
+ // Generate/bind a VBO to store instance attribute data
+ glGenBuffers(1, &app->instanceVbo);
+ glBindBuffer(GL_ARRAY_BUFFER, app->instanceVbo);
+ glBufferData(GL_ARRAY_BUFFER,
+ (GLsizeiptr)(app->numRects * sizeof(Rect)),
+ app->rects,
+ GL_STREAM_DRAW);
+
+ // Attribute 1 is Rect::position
+ glEnableVertexAttribArray(1);
+ glVertexAttribDivisor(1, 4);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), NULL);
+
+ // Attribute 2 is Rect::size
+ glEnableVertexAttribArray(2);
+ glVertexAttribDivisor(2, 4);
+ glVertexAttribPointer(
+ 2, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (const void*)offsetof(Rect, size));
+
+ // Attribute 3 is Rect::fillColor
+ glEnableVertexAttribArray(3);
+ glVertexAttribDivisor(3, 4);
+ glVertexAttribPointer(3,
+ 4,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(Rect),
+ (const void*)offsetof(Rect, fillColor));
+
+ // Set up the IBO to index into the VBO
+ glGenBuffers(1, &app->ibo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app->ibo);
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER, sizeof(rectIndices), rectIndices, GL_STATIC_DRAW);
+
+ return PUGL_SUCCESS;
+}
+
+static void
+teardownGl(PuglTestApp* app)
+{
+ glDeleteBuffers(1, &app->ibo);
+ glDeleteBuffers(1, &app->vbo);
+ glDeleteBuffers(1, &app->instanceVbo);
+ glDeleteVertexArrays(1, &app->vao);
+ deleteProgram(app->drawRect);
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTestApp app = {0};
+
+ app.programPath = argv[0];
+ app.glMajorVersion = 3;
+ app.glMinorVersion = 3;
+
+ // Parse command line options
+ if (parseOptions(&app, argc, argv)) {
+ puglPrintTestUsage("pugl_shader_demo", "[NUM_RECTS] [GL_MAJOR]");
+ return 1;
+ }
+
+ // Create and configure world and view
+ setupPugl(&app);
+
+ // Create window (which will send a PUGL_CREATE event)
+ const PuglStatus st = puglRealize(app.view);
+ if (st) {
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ // Show window
+ printViewHints(app.view);
+ puglShow(app.view);
+
+ // Calculate ideal frame duration to drive the main loop at a good rate
+ const int refreshRate = puglGetViewHint(app.view, PUGL_REFRESH_RATE);
+ const double frameDuration = 1.0 / (double)refreshRate;
+
+ // Grind away, drawing continuously
+ const double startTime = puglGetTime(app.world);
+ PuglFpsPrinter fpsPrinter = {startTime};
+ while (!app.quit) {
+ /* To minimize input latency and get smooth performance during window
+ resizing, we want to poll for events as long as possible before
+ starting to draw the next frame. This ensures that as many events
+ are consumed as possible before starting to draw, or, equivalently,
+ that the next rendered frame represents the latest events possible.
+ This is particularly important for mouse input and "live" window
+ resizing, where many events tend to pile up within a frame.
+
+ To do this, we keep track of the time when the last frame was
+ finished drawing, and how long it took to expose (and assume this is
+ relatively stable). Then, we can calculate how much time there is
+ from now until the time when we should start drawing to not miss the
+ deadline, and use that as the timeout for puglUpdate().
+ */
+
+ const double now = puglGetTime(app.world);
+ const double nextFrameEndTime = app.lastFrameEndTime + frameDuration;
+ const double nextExposeTime = nextFrameEndTime - app.lastDrawDuration;
+ const double timeUntilNext = nextExposeTime - now;
+ const double timeout = app.opts.sync ? timeUntilNext : 0.0;
+
+ puglUpdate(app.world, fmax(0.0, timeout));
+ puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn);
+ }
+
+ // Destroy window (which will send a PUGL_DESTROY event)
+ puglFreeView(app.view);
+
+ // Free everything else
+ puglFreeWorld(app.world);
+ free(app.rects);
+
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_vulkan_cxx_demo.cpp b/subprojects/d2tk/pugl/examples/pugl_vulkan_cxx_demo.cpp
new file mode 100644
index 0000000..d92e652
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_vulkan_cxx_demo.cpp
@@ -0,0 +1,1826 @@
+/*
+ Copyright 2019-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ An example of drawing with Vulkan.
+
+ This is an example of using Vulkan for pixel-perfect 2D drawing. It uses
+ the same data and shaders as pugl_shader_demo.c and attempts to draw the
+ same thing, except using Vulkan.
+
+ Since Vulkan is a complicated and very verbose API, this example is
+ unfortunately much larger than the others. You should not use this as a
+ resource to learn Vulkan, but it provides a decent demo of using Vulkan with
+ Pugl that works nicely on all supported platforms.
+*/
+
+#include "demo_utils.h"
+#include "file_utils.h"
+#include "rects.h"
+#include "test/test_utils.h"
+
+#include "sybok.hpp"
+
+#include "pugl/pugl.h"
+#include "pugl/pugl.hpp"
+#include "pugl/vulkan.hpp"
+
+#include <vulkan/vk_platform.h>
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace {
+
+constexpr uintptr_t resizeTimerId = 1u;
+
+struct PhysicalDeviceSelection {
+ sk::PhysicalDevice physicalDevice;
+ uint32_t graphicsFamilyIndex;
+};
+
+/// Basic Vulkan context associated with the window
+struct VulkanContext {
+ VkResult init(pugl::VulkanLoader& loader, const PuglTestOptions& opts);
+
+ sk::VulkanApi vk;
+ sk::Instance instance;
+ sk::DebugReportCallbackEXT debugCallback;
+};
+
+/// Basic setup of graphics device
+struct GraphicsDevice {
+ VkResult init(const pugl::VulkanLoader& loader,
+ const VulkanContext& context,
+ pugl::View& view,
+ const PuglTestOptions& opts);
+
+ sk::SurfaceKHR surface;
+ sk::PhysicalDevice physicalDevice{};
+ uint32_t graphicsIndex{};
+ VkSurfaceFormatKHR surfaceFormat{};
+ VkPresentModeKHR presentMode{};
+ VkPresentModeKHR resizePresentMode{};
+ sk::Device device{};
+ sk::Queue graphicsQueue{};
+ sk::CommandPool commandPool{};
+};
+
+/// Buffer allocated on the GPU
+struct Buffer {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ VkDeviceSize size,
+ VkBufferUsageFlags usage,
+ VkMemoryPropertyFlags properties);
+
+ sk::Buffer buffer;
+ sk::DeviceMemory deviceMemory;
+};
+
+/// A set of frames that can be rendered concurrently
+struct Swapchain {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ VkSurfaceCapabilitiesKHR capabilities,
+ VkExtent2D extent,
+ VkSwapchainKHR oldSwapchain,
+ bool resizing);
+
+ VkSurfaceCapabilitiesKHR capabilities{};
+ VkExtent2D extent{};
+ sk::SwapchainKHR swapchain{};
+ std::vector<sk::ImageView> imageViews{};
+};
+
+/// A pass that renders to a target
+struct RenderPass {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const Swapchain& swapchain);
+
+ sk::RenderPass renderPass;
+ std::vector<sk::Framebuffer> framebuffers;
+ sk::CommandBuffers<std::vector<VkCommandBuffer>> commandBuffers;
+};
+
+/// Uniform buffer for constant data used in shaders
+struct UniformBufferObject {
+ mat4 projection;
+};
+
+/// Rectangle data that does not depend on renderer configuration
+struct RectData {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ size_t nRects);
+
+ sk::DescriptorSetLayout descriptorSetLayout{};
+ Buffer uniformBuffer{};
+ sk::MappedMemory uniformData{};
+ Buffer modelBuffer{};
+ Buffer instanceBuffer{};
+ sk::MappedMemory vertexData{};
+ size_t numRects{};
+};
+
+/// Shader modules for drawing rectangles
+struct RectShaders {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const std::string& programPath);
+
+ sk::ShaderModule vert{};
+ sk::ShaderModule frag{};
+};
+
+/// A pipeline to render rectangles with our shaders
+struct RectPipeline {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const RectData& rectData,
+ const RectShaders& shaders,
+ const Swapchain& swapchain,
+ const RenderPass& renderPass);
+
+ sk::DescriptorPool descriptorPool{};
+ sk::DescriptorSets<std::vector<VkDescriptorSet>> descriptorSets{};
+ sk::PipelineLayout pipelineLayout{};
+ std::array<sk::Pipeline, 1> pipelines{};
+ uint32_t numImages{};
+};
+
+/// Synchronization primitives used to coordinate drawing frames
+struct RenderSync {
+ VkResult init(const sk::VulkanApi& vk,
+ const sk::Device& device,
+ uint32_t numImages);
+
+ std::vector<sk::Semaphore> imageAvailable{};
+ std::vector<sk::Semaphore> renderFinished{};
+ std::vector<sk::Fence> inFlight{};
+ size_t currentFrame{};
+};
+
+/// Renderer that owns the above and everything required to draw
+struct Renderer {
+ VkResult init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const RectData& rectData,
+ const RectShaders& rectShaders,
+ VkExtent2D extent,
+ bool resizing);
+
+ VkResult recreate(const sk::VulkanApi& vk,
+ const sk::SurfaceKHR& surface,
+ const GraphicsDevice& gpu,
+ const RectData& rectData,
+ const RectShaders& rectShaders,
+ VkExtent2D extent,
+ bool resizing);
+
+ Swapchain swapchain;
+ RenderPass renderPass;
+ RectPipeline rectPipeline;
+ RenderSync sync;
+};
+
+VkResult
+selectSurfaceFormat(const sk::VulkanApi& vk,
+ const sk::PhysicalDevice& physicalDevice,
+ const sk::SurfaceKHR& surface,
+ VkSurfaceFormatKHR& surfaceFormat)
+{
+ std::vector<VkSurfaceFormatKHR> formats;
+ if (VkResult r = vk.getPhysicalDeviceSurfaceFormatsKHR(
+ physicalDevice, surface, formats)) {
+ return r;
+ }
+
+ for (const auto& format : formats) {
+ if (format.format == VK_FORMAT_B8G8R8A8_UNORM &&
+ format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+ surfaceFormat = format;
+ return VK_SUCCESS;
+ }
+ }
+
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+}
+
+VkResult
+selectPresentMode(const sk::VulkanApi& vk,
+ const sk::PhysicalDevice& physicalDevice,
+ const sk::SurfaceKHR& surface,
+ const bool multiBuffer,
+ const bool sync,
+ VkPresentModeKHR& presentMode)
+{
+ // Map command line options to mode priorities
+ static constexpr VkPresentModeKHR priorities[][2][4] = {
+ {
+ // No double buffer, no sync
+ {VK_PRESENT_MODE_IMMEDIATE_KHR,
+ VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+ VK_PRESENT_MODE_FIFO_KHR},
+
+ // No double buffer, sync (nonsense, map to FIFO relaxed)
+ {VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+ VK_PRESENT_MODE_FIFO_KHR,
+ VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_IMMEDIATE_KHR},
+ },
+ {
+ // Double buffer, no sync
+ {
+ VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_IMMEDIATE_KHR,
+ VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+ VK_PRESENT_MODE_FIFO_KHR,
+ },
+
+ // Double buffer, sync
+ {VK_PRESENT_MODE_FIFO_KHR,
+ VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+ VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_IMMEDIATE_KHR},
+ },
+ };
+
+ std::vector<VkPresentModeKHR> modes;
+ if (VkResult r = vk.getPhysicalDeviceSurfacePresentModesKHR(
+ physicalDevice, surface, modes)) {
+ return r;
+ }
+
+ const auto& tryModes = priorities[bool(multiBuffer)][bool(sync)];
+ for (const auto m : tryModes) {
+ if (std::find(modes.begin(), modes.end(), m) != modes.end()) {
+ presentMode = m;
+ return VK_SUCCESS;
+ }
+ }
+
+ return VK_ERROR_INCOMPATIBLE_DRIVER;
+}
+
+VkResult
+openDevice(const sk::VulkanApi& vk,
+ const sk::PhysicalDevice& physicalDevice,
+ const uint32_t graphicsFamilyIndex,
+ sk::Device& device)
+{
+ const float graphicsQueuePriority = 1.0f;
+ const char* const swapchainName = "VK_KHR_swapchain";
+
+ const VkDeviceQueueCreateInfo queueCreateInfo{
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ nullptr,
+ 0u,
+ graphicsFamilyIndex,
+ SK_COUNTED(1u, &graphicsQueuePriority),
+ };
+
+ const VkDeviceCreateInfo createInfo{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ nullptr,
+ 0u,
+ SK_COUNTED(1u, &queueCreateInfo),
+ SK_COUNTED(0u, nullptr), // Deprecated
+ SK_COUNTED(1u, &swapchainName),
+ nullptr};
+
+ return vk.createDevice(physicalDevice, createInfo, device);
+}
+
+/// Return whether the physical device supports the extensions we require
+VkResult
+deviceSupportsRequiredExtensions(const sk::VulkanApi& vk,
+ const sk::PhysicalDevice& device,
+ bool& supported)
+{
+ VkResult r = VK_SUCCESS;
+
+ std::vector<VkExtensionProperties> props;
+ if ((r = vk.enumerateDeviceExtensionProperties(device, props))) {
+ return r;
+ }
+
+ supported = std::any_of(
+ props.begin(), props.end(), [&](const VkExtensionProperties& e) {
+ return !strcmp(e.extensionName, "VK_KHR_swapchain");
+ });
+
+ return VK_SUCCESS;
+}
+
+/// Return the index of the graphics queue, if there is one
+VkResult
+findGraphicsQueue(const sk::VulkanApi& vk,
+ const sk::SurfaceKHR& surface,
+ const sk::PhysicalDevice& device,
+ uint32_t& queueIndex)
+{
+ VkResult r = VK_SUCCESS;
+
+ std::vector<VkQueueFamilyProperties> queueProps;
+ if ((r = vk.getPhysicalDeviceQueueFamilyProperties(device, queueProps))) {
+ return r;
+ }
+
+ for (uint32_t q = 0u; q < queueProps.size(); ++q) {
+ if (queueProps[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ bool supported = false;
+ if ((r = vk.getPhysicalDeviceSurfaceSupportKHR(
+ device, q, surface, supported))) {
+ return r;
+ }
+
+ if (supported) {
+ queueIndex = q;
+ return VK_SUCCESS;
+ }
+ }
+ }
+
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+}
+
+/// Select a physical graphics device to use (simply the first found)
+VkResult
+selectPhysicalDevice(const sk::VulkanApi& vk,
+ const sk::Instance& instance,
+ const sk::SurfaceKHR& surface,
+ PhysicalDeviceSelection& selection)
+{
+ VkResult r = VK_SUCCESS;
+
+ std::vector<sk::PhysicalDevice> devices;
+ if ((r = vk.enumeratePhysicalDevices(instance, devices))) {
+ return r;
+ }
+
+ for (const auto& device : devices) {
+ auto supported = false;
+ if ((r = deviceSupportsRequiredExtensions(vk, device, supported))) {
+ return r;
+ }
+
+ if (supported) {
+ auto queueIndex = 0u;
+ if ((r = findGraphicsQueue(vk, surface, device, queueIndex))) {
+ return r;
+ }
+
+ selection = PhysicalDeviceSelection{device, queueIndex};
+ return VK_SUCCESS;
+ }
+ }
+
+ return VK_ERROR_INCOMPATIBLE_DISPLAY_KHR;
+}
+
+VkResult
+GraphicsDevice::init(const pugl::VulkanLoader& loader,
+ const VulkanContext& context,
+ pugl::View& view,
+ const PuglTestOptions& opts)
+{
+ const auto& vk = context.vk;
+ VkResult r = VK_SUCCESS;
+
+ // Create a Vulkan surface for the window using the Pugl API
+ VkSurfaceKHR surfaceHandle = {};
+ if ((r = pugl::createSurface(loader.getInstanceProcAddrFunc(),
+ view,
+ context.instance,
+ nullptr,
+ &surfaceHandle))) {
+ return r;
+ }
+
+ // Wrap surface in a safe RAII handle
+ surface =
+ sk::SurfaceKHR{surfaceHandle, {context.instance, vk.vkDestroySurfaceKHR}};
+
+ PhysicalDeviceSelection physicalDeviceSelection = {};
+ // Select a physical device to use
+ if ((r = selectPhysicalDevice(
+ vk, context.instance, surface, physicalDeviceSelection))) {
+ return r;
+ }
+
+ physicalDevice = physicalDeviceSelection.physicalDevice;
+ graphicsIndex = physicalDeviceSelection.graphicsFamilyIndex;
+
+ if ((r = selectSurfaceFormat(vk, physicalDevice, surface, surfaceFormat)) ||
+ (r = selectPresentMode(vk,
+ physicalDevice,
+ surface,
+ opts.doubleBuffer,
+ opts.sync,
+ presentMode)) ||
+ (r = selectPresentMode(
+ vk, physicalDevice, surface, true, false, resizePresentMode)) ||
+ (r = openDevice(vk, physicalDevice, graphicsIndex, device))) {
+ return r;
+ }
+
+ const VkCommandPoolCreateInfo commandPoolInfo{
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, {}, graphicsIndex};
+
+ if ((r = vk.createCommandPool(device, commandPoolInfo, commandPool))) {
+ return r;
+ }
+
+ graphicsQueue = vk.getDeviceQueue(device, graphicsIndex, 0);
+ return VK_SUCCESS;
+}
+
+uint32_t
+findMemoryType(const sk::VulkanApi& vk,
+ const sk::PhysicalDevice& physicalDevice,
+ const uint32_t typeFilter,
+ const VkMemoryPropertyFlags& properties)
+{
+ VkPhysicalDeviceMemoryProperties memProperties =
+ vk.getPhysicalDeviceMemoryProperties(physicalDevice);
+
+ for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) {
+ if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags &
+ properties) == properties) {
+ return i;
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+VkResult
+Buffer::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const VkDeviceSize size,
+ const VkBufferUsageFlags usage,
+ const VkMemoryPropertyFlags properties)
+{
+ const VkBufferCreateInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ nullptr,
+ {},
+ size,
+ usage,
+ VK_SHARING_MODE_EXCLUSIVE,
+ SK_COUNTED(0, nullptr)};
+
+ const auto& device = gpu.device;
+
+ VkResult r = VK_SUCCESS;
+ if ((r = vk.createBuffer(device, bufferInfo, buffer))) {
+ return r;
+ }
+
+ const auto requirements = vk.getBufferMemoryRequirements(device, buffer);
+ const auto memoryTypeIndex = findMemoryType(
+ vk, gpu.physicalDevice, requirements.memoryTypeBits, properties);
+
+ if (memoryTypeIndex == UINT32_MAX) {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+
+ const VkMemoryAllocateInfo allocInfo{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ requirements.size,
+ memoryTypeIndex};
+
+ if ((r = vk.allocateMemory(device, allocInfo, deviceMemory)) ||
+ (r = vk.bindBufferMemory(device, buffer, deviceMemory, 0))) {
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult
+Swapchain::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const VkSurfaceCapabilitiesKHR surfaceCapabilities,
+ const VkExtent2D surfaceExtent,
+ VkSwapchainKHR oldSwapchain,
+ bool resizing)
+{
+ capabilities = surfaceCapabilities;
+ extent = surfaceExtent;
+
+ const auto minNumImages =
+ (!capabilities.maxImageCount || capabilities.maxImageCount >= 3u)
+ ? 3u
+ : capabilities.maxImageCount;
+
+ const VkSwapchainCreateInfoKHR swapchainCreateInfo{
+ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ nullptr,
+ {},
+ gpu.surface,
+ minNumImages,
+ gpu.surfaceFormat.format,
+ gpu.surfaceFormat.colorSpace,
+ surfaceExtent,
+ 1,
+ (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT),
+ VK_SHARING_MODE_EXCLUSIVE,
+ SK_COUNTED(0, nullptr),
+ capabilities.currentTransform,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ resizing ? gpu.resizePresentMode : gpu.presentMode,
+ VK_TRUE,
+ oldSwapchain};
+
+ VkResult r = VK_SUCCESS;
+ std::vector<VkImage> images;
+ if ((r = vk.createSwapchainKHR(gpu.device, swapchainCreateInfo, swapchain)) ||
+ (r = vk.getSwapchainImagesKHR(gpu.device, swapchain, images))) {
+ return r;
+ }
+
+ imageViews = std::vector<sk::ImageView>(images.size());
+ for (size_t i = 0; i < images.size(); ++i) {
+ const VkImageViewCreateInfo imageViewCreateInfo{
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ nullptr,
+ {},
+ images[i],
+ VK_IMAGE_VIEW_TYPE_2D,
+ gpu.surfaceFormat.format,
+ {},
+ {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
+
+ if ((r = vk.createImageView(
+ gpu.device, imageViewCreateInfo, imageViews[i]))) {
+ return r;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult
+RenderPass::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const Swapchain& swapchain)
+{
+ const auto numImages = static_cast<uint32_t>(swapchain.imageViews.size());
+
+ assert(numImages > 0);
+
+ // Create command buffers
+ const VkCommandBufferAllocateInfo commandBufferAllocateInfo{
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ nullptr,
+ gpu.commandPool,
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ numImages};
+
+ VkResult r = VK_SUCCESS;
+ if ((r = vk.allocateCommandBuffers(
+ gpu.device, commandBufferAllocateInfo, commandBuffers))) {
+ return r;
+ }
+
+ static constexpr VkAttachmentReference colorAttachmentRef{
+ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
+
+ static constexpr VkSubpassDescription subpass{
+ {},
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ SK_COUNTED(0, nullptr),
+ SK_COUNTED(1, &colorAttachmentRef, nullptr, nullptr),
+ SK_COUNTED(0u, nullptr)};
+
+ static constexpr VkSubpassDependency dependency{
+ VK_SUBPASS_EXTERNAL,
+ 0,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
+ {},
+ {}};
+
+ const VkAttachmentDescription colorAttachment{
+ {},
+ gpu.surfaceFormat.format,
+ VK_SAMPLE_COUNT_1_BIT,
+ VK_ATTACHMENT_LOAD_OP_CLEAR,
+ VK_ATTACHMENT_STORE_OP_STORE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ };
+
+ const VkRenderPassCreateInfo renderPassCreateInfo{
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ nullptr,
+ {},
+ SK_COUNTED(1, &colorAttachment),
+ SK_COUNTED(1, &subpass),
+ SK_COUNTED(1, &dependency)};
+
+ if ((r = vk.createRenderPass(gpu.device, renderPassCreateInfo, renderPass))) {
+ return r;
+ }
+
+ // Create framebuffers
+ framebuffers = std::vector<sk::Framebuffer>(numImages);
+ for (uint32_t i = 0; i < numImages; ++i) {
+ const VkFramebufferCreateInfo framebufferCreateInfo{
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+ nullptr,
+ {},
+ renderPass,
+ SK_COUNTED(1, &swapchain.imageViews[i].get()),
+ swapchain.extent.width,
+ swapchain.extent.height,
+ 1};
+
+ if ((r = vk.createFramebuffer(
+ gpu.device, framebufferCreateInfo, framebuffers[i]))) {
+ return r;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+std::vector<uint32_t>
+readFile(const char* const programPath, const std::string& filename)
+{
+ std::unique_ptr<char, decltype(&free)> path{
+ resourcePath(programPath, filename.c_str()), &free};
+
+ std::cerr << "Loading shader: " << path.get() << std::endl;
+
+ std::unique_ptr<FILE, decltype(&fclose)> file{fopen(path.get(), "rb"),
+ &fclose};
+
+ if (!file) {
+ std::cerr << "Failed to open file '" << filename << "'\n";
+ return {};
+ }
+
+ fseek(file.get(), 0, SEEK_END);
+ const auto fileSize = static_cast<size_t>(ftell(file.get()));
+ fseek(file.get(), 0, SEEK_SET);
+
+ const auto numWords = fileSize / sizeof(uint32_t);
+ std::vector<uint32_t> buffer(numWords);
+
+ fread(buffer.data(), sizeof(uint32_t), numWords, file.get());
+
+ return buffer;
+}
+
+VkResult
+createShaderModule(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const std::vector<uint32_t>& code,
+ sk::ShaderModule& shaderModule)
+{
+ const VkShaderModuleCreateInfo createInfo{
+ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ nullptr,
+ {},
+ code.size() * sizeof(uint32_t),
+ code.data()};
+
+ return vk.createShaderModule(gpu.device, createInfo, shaderModule);
+}
+
+VkResult
+RectShaders::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const std::string& programPath)
+{
+ auto vertShaderCode = readFile(programPath.c_str(), "shaders/rect.vert.spv");
+
+ auto fragShaderCode = readFile(programPath.c_str(), "shaders/rect.frag.spv");
+
+ if (vertShaderCode.empty() || fragShaderCode.empty()) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ VkResult r = VK_SUCCESS;
+ if ((r = createShaderModule(vk, gpu, vertShaderCode, vert)) ||
+ (r = createShaderModule(vk, gpu, fragShaderCode, frag))) {
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult
+RectPipeline::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const RectData& rectData,
+ const RectShaders& shaders,
+ const Swapchain& swapchain,
+ const RenderPass& renderPass)
+{
+ const auto oldNumImages = numImages;
+ VkResult r = VK_SUCCESS;
+
+ numImages = static_cast<uint32_t>(swapchain.imageViews.size());
+ pipelines = {};
+ pipelineLayout = {};
+ descriptorSets = {};
+
+ if (numImages != oldNumImages) {
+ // Create layout descriptor pool
+
+ const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ numImages};
+
+ const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
+ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ nullptr,
+ VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
+ numImages,
+ 1u,
+ &poolSize};
+ if ((r = vk.createDescriptorPool(
+ gpu.device, descriptorPoolCreateInfo, descriptorPool))) {
+ return r;
+ }
+ }
+
+ const std::vector<VkDescriptorSetLayout> layouts(
+ numImages, rectData.descriptorSetLayout.get());
+
+ const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ nullptr,
+ descriptorPool,
+ numImages,
+ layouts.data()};
+ if ((r = vk.allocateDescriptorSets(
+ gpu.device, descriptorSetAllocateInfo, descriptorSets))) {
+ return r;
+ }
+
+ const VkDescriptorBufferInfo bufferInfo{
+ rectData.uniformBuffer.buffer, 0, sizeof(UniformBufferObject)};
+
+ const std::array<VkWriteDescriptorSet, 1> descriptorWrites{
+ {{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ nullptr,
+ descriptorSets[0],
+ 0,
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ nullptr,
+ &bufferInfo,
+ nullptr}}};
+
+ const std::array<VkCopyDescriptorSet, 0> descriptorCopies{};
+
+ vk.updateDescriptorSets(gpu.device, descriptorWrites, descriptorCopies);
+
+ static constexpr std::array<VkVertexInputAttributeDescription, 4>
+ vertexAttributeDescriptions{
+ {// Model
+ {0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0},
+
+ // Rect instance attributes
+ {1u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, pos)},
+ {2u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, size)},
+ {3u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Rect, fillColor)}}};
+
+ static constexpr std::array<VkVertexInputBindingDescription, 2>
+ vertexBindingDescriptions{
+ VkVertexInputBindingDescription{
+ 0, sizeof(vec2), VK_VERTEX_INPUT_RATE_VERTEX},
+ VkVertexInputBindingDescription{
+ 1u, sizeof(Rect), VK_VERTEX_INPUT_RATE_INSTANCE}};
+
+ static constexpr VkPipelineInputAssemblyStateCreateInfo inputAssembly{
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ nullptr,
+ {},
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ false};
+
+ static constexpr VkPipelineRasterizationStateCreateInfo rasterizer{
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ nullptr,
+ {},
+ 0,
+ 0,
+ VK_POLYGON_MODE_FILL,
+ VK_CULL_MODE_BACK_BIT,
+ VK_FRONT_FACE_CLOCKWISE,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1.0f};
+
+ static constexpr VkPipelineMultisampleStateCreateInfo multisampling{
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ nullptr,
+ {},
+ VK_SAMPLE_COUNT_1_BIT,
+ false,
+ 0.0f,
+ nullptr,
+ false,
+ false};
+
+ static constexpr VkPipelineColorBlendAttachmentState colorBlendAttachment{
+ true,
+ VK_BLEND_FACTOR_SRC_ALPHA,
+ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+ VK_BLEND_OP_ADD,
+ VK_BLEND_FACTOR_ONE,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)};
+
+ const VkPipelineShaderStageCreateInfo shaderStages[] = {
+ {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ {},
+ VK_SHADER_STAGE_VERTEX_BIT,
+ shaders.vert.get(),
+ "main",
+ nullptr},
+ {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ {},
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ shaders.frag.get(),
+ "main",
+ nullptr}};
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputInfo{
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ nullptr,
+ {},
+ SK_COUNTED(static_cast<uint32_t>(vertexBindingDescriptions.size()),
+ vertexBindingDescriptions.data()),
+ SK_COUNTED(static_cast<uint32_t>(vertexAttributeDescriptions.size()),
+ vertexAttributeDescriptions.data())};
+
+ const VkViewport viewport{0.0f,
+ 0.0f,
+ float(swapchain.extent.width),
+ float(swapchain.extent.height),
+ 0.0f,
+ 1.0f};
+
+ const VkRect2D scissor{{0, 0}, swapchain.extent};
+
+ const VkPipelineViewportStateCreateInfo viewportState{
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ nullptr,
+ {},
+ SK_COUNTED(1, &viewport),
+ SK_COUNTED(1, &scissor)};
+
+ const VkPipelineColorBlendStateCreateInfo colorBlending{
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ nullptr,
+ {},
+ false,
+ VK_LOGIC_OP_COPY,
+ SK_COUNTED(1, &colorBlendAttachment),
+ {1.0f, 0.0f, 0.0f, 0.0f}};
+
+ const VkPipelineLayoutCreateInfo layoutInfo{
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ nullptr,
+ {},
+ SK_COUNTED(1, &rectData.descriptorSetLayout.get()),
+ SK_COUNTED(0, nullptr)};
+
+ if ((r = vk.createPipelineLayout(gpu.device, layoutInfo, pipelineLayout))) {
+ return r;
+ }
+
+ const std::array<VkGraphicsPipelineCreateInfo, 1> pipelineInfos{
+ {{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ nullptr,
+ {},
+ SK_COUNTED(2, shaderStages),
+ &vertexInputInfo,
+ &inputAssembly,
+ nullptr,
+ &viewportState,
+ &rasterizer,
+ &multisampling,
+ nullptr,
+ &colorBlending,
+ nullptr,
+ pipelineLayout,
+ renderPass.renderPass,
+ 0u,
+ {},
+ 0}}};
+
+ if ((r = vk.createGraphicsPipelines(
+ gpu.device, {}, pipelineInfos, pipelines))) {
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult
+RectData::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const size_t nRects)
+{
+ numRects = nRects;
+
+ static constexpr VkDescriptorSetLayoutBinding uboLayoutBinding{
+ 0,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ nullptr};
+
+ const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ nullptr,
+ {},
+ 1,
+ &uboLayoutBinding};
+
+ VkResult r = VK_SUCCESS;
+ if ((r = vk.createDescriptorSetLayout(
+ gpu.device, descriptorSetLayoutInfo, descriptorSetLayout)) ||
+ (r = uniformBuffer.init(vk,
+ gpu,
+ sizeof(UniformBufferObject),
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ||
+ (r = vk.mapMemory(gpu.device,
+ uniformBuffer.deviceMemory,
+ 0,
+ sizeof(UniformBufferObject),
+ {},
+ uniformData))) {
+ return r;
+ }
+
+ const VkBufferUsageFlags usageFlags =
+ (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+
+ const VkMemoryPropertyFlags propertyFlags =
+ (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ if ((r = modelBuffer.init(
+ vk, gpu, sizeof(rectVertices), usageFlags, propertyFlags))) {
+ return r;
+ }
+
+ {
+ // Copy model vertices (directly, we do this only once)
+ sk::MappedMemory modelData;
+ if ((r = vk.mapMemory(gpu.device,
+ modelBuffer.deviceMemory,
+ 0,
+ static_cast<VkDeviceSize>(sizeof(rectVertices)),
+ {},
+ modelData))) {
+ return r;
+ }
+
+ memcpy(modelData.get(), rectVertices, sizeof(rectVertices));
+ }
+
+ if ((r = instanceBuffer.init(
+ vk, gpu, sizeof(Rect) * numRects, usageFlags, propertyFlags))) {
+ return r;
+ }
+
+ // Map attribute vertices (we will update them every frame)
+ const auto rectsSize = static_cast<VkDeviceSize>(sizeof(Rect) * numRects);
+ if ((r = vk.mapMemory(gpu.device,
+ instanceBuffer.deviceMemory,
+ 0,
+ rectsSize,
+ {},
+ vertexData))) {
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult
+RenderSync::init(const sk::VulkanApi& vk,
+ const sk::Device& device,
+ const uint32_t numImages)
+{
+ const auto maxInFlight = std::max(1u, numImages - 1u);
+ VkResult r = VK_SUCCESS;
+
+ imageAvailable = std::vector<sk::Semaphore>(numImages);
+ renderFinished = std::vector<sk::Semaphore>(numImages);
+ for (uint32_t i = 0; i < numImages; ++i) {
+ static constexpr VkSemaphoreCreateInfo semaphoreInfo{
+ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, {}};
+
+ if ((r = vk.createSemaphore(device, semaphoreInfo, imageAvailable[i])) ||
+ (r = vk.createSemaphore(device, semaphoreInfo, renderFinished[i]))) {
+ return r;
+ }
+ }
+
+ inFlight = std::vector<sk::Fence>(maxInFlight);
+ for (uint32_t i = 0; i < maxInFlight; ++i) {
+ static constexpr VkFenceCreateInfo fenceInfo{
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+ nullptr,
+ VK_FENCE_CREATE_SIGNALED_BIT};
+
+ if ((r = vk.createFence(device, fenceInfo, inFlight[i]))) {
+ return r;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult
+Renderer::init(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const RectData& rectData,
+ const RectShaders& rectShaders,
+ const VkExtent2D extent,
+ bool resizing)
+{
+ VkResult r = VK_SUCCESS;
+ VkSurfaceCapabilitiesKHR capabilities = {};
+
+ if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR(
+ gpu.physicalDevice, gpu.surface, capabilities)) ||
+ (r = swapchain.init(vk, gpu, capabilities, extent, {}, resizing)) ||
+ (r = renderPass.init(vk, gpu, swapchain)) ||
+ (r = rectPipeline.init(
+ vk, gpu, rectData, rectShaders, swapchain, renderPass))) {
+ return r;
+ }
+
+ const auto numFrames = static_cast<uint32_t>(swapchain.imageViews.size());
+ return sync.init(vk, gpu.device, numFrames);
+}
+
+VkResult
+Renderer::recreate(const sk::VulkanApi& vk,
+ const sk::SurfaceKHR& surface,
+ const GraphicsDevice& gpu,
+ const RectData& rectData,
+ const RectShaders& rectShaders,
+ const VkExtent2D extent,
+ bool resizing)
+{
+ VkResult r = VK_SUCCESS;
+ const auto oldNumImages = swapchain.imageViews.size();
+
+ VkSurfaceCapabilitiesKHR capabilities = {};
+ if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR(
+ gpu.physicalDevice, surface, capabilities)) ||
+ (r = swapchain.init(
+ vk, gpu, capabilities, extent, swapchain.swapchain, resizing)) ||
+ (r = renderPass.init(vk, gpu, swapchain)) ||
+ (r = rectPipeline.init(
+ vk, gpu, rectData, rectShaders, swapchain, renderPass))) {
+ return r;
+ }
+
+ const auto numFrames = static_cast<uint32_t>(swapchain.imageViews.size());
+ if (swapchain.imageViews.size() != oldNumImages) {
+ return sync.init(vk, gpu.device, numFrames);
+ }
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR
+VkBool32 VKAPI_CALL
+debugCallback(VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT,
+ uint64_t,
+ size_t,
+ int32_t,
+ const char* layerPrefix,
+ const char* msg,
+ void*)
+{
+ std::cerr << sk::string(static_cast<VkDebugReportFlagBitsEXT>(flags)) << ": "
+ << layerPrefix << ": " << msg << std::endl;
+
+ return VK_FALSE;
+}
+
+bool
+hasExtension(const char* name,
+ const std::vector<VkExtensionProperties>& properties)
+{
+ for (const auto& p : properties) {
+ if (!strcmp(p.extensionName, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+hasLayer(const char* name, const std::vector<VkLayerProperties>& properties)
+{
+ for (const auto& p : properties) {
+ if (!strcmp(p.layerName, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template<class Value>
+void
+logInfo(const char* heading, const Value& value)
+{
+ std::cout << std::setw(26) << std::left << (std::string(heading) + ":")
+ << value << std::endl;
+}
+
+VkResult
+createInstance(sk::VulkanInitApi& initApi,
+ const PuglTestOptions& opts,
+ sk::Instance& instance)
+{
+ VkResult r = VK_SUCCESS;
+
+ std::vector<VkLayerProperties> layerProps;
+ std::vector<VkExtensionProperties> extProps;
+ if ((r = initApi.enumerateInstanceLayerProperties(layerProps)) ||
+ (r = initApi.enumerateInstanceExtensionProperties(extProps))) {
+ return r;
+ }
+
+ const auto puglExtensions = pugl::getInstanceExtensions();
+ auto extensions =
+ std::vector<const char*>(puglExtensions.begin(), puglExtensions.end());
+
+ // Add extra extensions we want to use if they are supported
+ if (hasExtension("VK_EXT_debug_report", extProps)) {
+ extensions.push_back("VK_EXT_debug_report");
+ }
+
+ // Add validation layers if error checking is enabled
+ std::vector<const char*> layers;
+ if (opts.errorChecking) {
+ for (const char* l : {"VK_LAYER_KHRONOS_validation",
+ "VK_LAYER_LUNARG_standard_validation"}) {
+ if (hasLayer(l, layerProps)) {
+ layers.push_back(l);
+ }
+ }
+ }
+
+ for (const auto& e : extensions) {
+ logInfo("Using instance extension", e);
+ }
+
+ for (const auto& l : layers) {
+ logInfo("Using instance layer", l);
+ }
+
+ static constexpr VkApplicationInfo appInfo{
+ VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ nullptr,
+ "Pugl Vulkan Demo",
+ 0,
+ nullptr,
+ 0,
+ VK_MAKE_VERSION(1, 0, 0),
+ };
+
+ const VkInstanceCreateInfo createInfo{
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ nullptr,
+ VkInstanceCreateFlags{},
+ &appInfo,
+ SK_COUNTED(uint32_t(layers.size()), layers.data()),
+ SK_COUNTED(uint32_t(extensions.size()), extensions.data())};
+
+ return initApi.createInstance(createInfo, instance);
+}
+
+VkResult
+getDebugReportCallback(sk::VulkanApi& api,
+ sk::Instance& instance,
+ const bool verbose,
+ sk::DebugReportCallbackEXT& callback)
+{
+ if (api.vkCreateDebugReportCallbackEXT) {
+ VkDebugReportFlagsEXT flags = (VK_DEBUG_REPORT_WARNING_BIT_EXT |
+ VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
+ VK_DEBUG_REPORT_ERROR_BIT_EXT);
+
+ if (verbose) {
+ flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
+ flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+ }
+
+ const VkDebugReportCallbackCreateInfoEXT createInfo{
+ VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
+ nullptr,
+ flags,
+ debugCallback,
+ nullptr};
+
+ return api.createDebugReportCallbackEXT(instance, createInfo, callback);
+ }
+
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+}
+
+void
+recordCommandBuffer(sk::CommandScope& cmd,
+ const Swapchain& swapchain,
+ const RenderPass& renderPass,
+ const RectPipeline& rectPipeline,
+ const RectData& rectData,
+ const size_t imageIndex)
+{
+ const VkClearColorValue clearColorValue{{0.0f, 0.0f, 0.0f, 1.0f}};
+ const VkClearValue clearValue{clearColorValue};
+
+ const VkRenderPassBeginInfo renderPassBegin{
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ nullptr,
+ renderPass.renderPass,
+ renderPass.framebuffers[imageIndex],
+ VkRect2D{{0, 0}, swapchain.extent},
+ SK_COUNTED(1, &clearValue)};
+
+ auto pass = cmd.beginRenderPass(renderPassBegin, VK_SUBPASS_CONTENTS_INLINE);
+
+ pass.bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, rectPipeline.pipelines[0]);
+
+ const std::array<VkDeviceSize, 1> offsets{0};
+ pass.bindVertexBuffers(
+ 0u, SK_COUNTED(1u, &rectData.modelBuffer.buffer.get(), offsets.data()));
+
+ pass.bindVertexBuffers(
+ 1u, SK_COUNTED(1u, &rectData.instanceBuffer.buffer.get(), offsets.data()));
+
+ pass.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
+ rectPipeline.pipelineLayout,
+ 0u,
+ SK_COUNTED(1u, rectPipeline.descriptorSets.get()),
+ 0u,
+ nullptr);
+
+ pass.draw(4u, static_cast<uint32_t>(rectData.numRects), 0u, 0u);
+}
+
+VkResult
+recordCommandBuffers(const sk::VulkanApi& vk,
+ const Swapchain& swapchain,
+ const RenderPass& renderPass,
+ const RectPipeline& rectPipeline,
+ const RectData& rectData)
+{
+ VkResult r = VK_SUCCESS;
+
+ for (size_t i = 0; i < swapchain.imageViews.size(); ++i) {
+ const VkCommandBufferBeginInfo beginInfo{
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ nullptr,
+ VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
+ nullptr};
+
+ auto* const commandBuffer = renderPass.commandBuffers[i];
+ auto cmd = vk.beginCommandBuffer(commandBuffer, beginInfo);
+ if (!cmd) {
+ return cmd.error();
+ }
+
+ recordCommandBuffer(cmd, swapchain, renderPass, rectPipeline, rectData, i);
+
+ if ((r = cmd.end())) {
+ return r;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+class PuglVulkanDemo;
+
+class View : public pugl::View
+{
+public:
+ View(pugl::World& world, PuglVulkanDemo& app)
+ : pugl::View{world}
+ , _app{app}
+ {
+ setEventHandler(*this);
+ }
+
+ template<PuglEventType t, class Base>
+ pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept
+ {
+ return pugl::Status::success;
+ }
+
+ pugl::Status onEvent(const pugl::ConfigureEvent& event);
+ pugl::Status onEvent(const pugl::UpdateEvent& event);
+ pugl::Status onEvent(const pugl::ExposeEvent& event);
+ pugl::Status onEvent(const pugl::LoopEnterEvent& event);
+ pugl::Status onEvent(const pugl::TimerEvent& event);
+ pugl::Status onEvent(const pugl::LoopLeaveEvent& event);
+ pugl::Status onEvent(const pugl::KeyPressEvent& event);
+ pugl::Status onEvent(const pugl::CloseEvent& event);
+
+private:
+ PuglVulkanDemo& _app;
+};
+
+class PuglVulkanDemo
+{
+public:
+ PuglVulkanDemo(const char* executablePath,
+ const PuglTestOptions& o,
+ size_t numRects);
+
+ const char* programPath;
+ PuglTestOptions opts;
+ pugl::World world;
+ pugl::VulkanLoader loader;
+ View view;
+ VulkanContext vulkan;
+ GraphicsDevice gpu;
+ Renderer renderer;
+ RectData rectData;
+ RectShaders rectShaders;
+ uint32_t framesDrawn{0};
+ VkExtent2D extent{512u, 512u};
+ std::vector<Rect> rects;
+ bool resizing{false};
+ bool quit{false};
+};
+
+std::vector<Rect>
+makeRects(const size_t numRects, const uint32_t windowWidth)
+{
+ std::vector<Rect> rects(numRects);
+ for (size_t i = 0; i < numRects; ++i) {
+ rects[i] = makeRect(i, static_cast<float>(windowWidth));
+ }
+
+ return rects;
+}
+
+PuglVulkanDemo::PuglVulkanDemo(const char* const executablePath,
+ const PuglTestOptions& o,
+ const size_t numRects)
+ : programPath{executablePath}
+ , opts{o}
+ , world{pugl::WorldType::program, pugl::WorldFlag::threads}
+ , loader{world}
+ , view{world, *this}
+ , rects{makeRects(numRects, extent.width)}
+{}
+
+VkResult
+recreateRenderer(PuglVulkanDemo& app,
+ const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const VkExtent2D extent,
+ const RectData& rectData,
+ const RectShaders& rectShaders)
+{
+ VkResult r = VK_SUCCESS;
+ VkSurfaceCapabilitiesKHR capabilities = {};
+ if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR(
+ gpu.physicalDevice, gpu.surface, capabilities))) {
+ return r;
+ }
+
+ // There is a known race issue here, so we clamp and hope for the best
+ const VkExtent2D clampedExtent{
+ std::min(capabilities.maxImageExtent.width,
+ std::max(capabilities.minImageExtent.width, extent.width)),
+ std::min(capabilities.maxImageExtent.height,
+ std::max(capabilities.minImageExtent.height, extent.height))};
+
+ if ((r = vk.deviceWaitIdle(gpu.device)) ||
+ (r = app.renderer.recreate(vk,
+ gpu.surface,
+ gpu,
+ rectData,
+ rectShaders,
+ clampedExtent,
+ app.resizing))) {
+ return r;
+ }
+
+ // Reset current (initially signaled) fence because we already waited
+ vk.resetFence(gpu.device,
+ app.renderer.sync.inFlight[app.renderer.sync.currentFrame]);
+
+ // Record new command buffers
+ return recordCommandBuffers(vk,
+ app.renderer.swapchain,
+ app.renderer.renderPass,
+ app.renderer.rectPipeline,
+ rectData);
+}
+
+pugl::Status
+View::onEvent(const pugl::ConfigureEvent& event)
+{
+ // We just record the size here and lazily resize the surface when exposed
+ _app.extent = {static_cast<uint32_t>(event.width),
+ static_cast<uint32_t>(event.height)};
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+View::onEvent(const pugl::UpdateEvent&)
+{
+ return postRedisplay();
+}
+
+VkResult
+beginFrame(PuglVulkanDemo& app, const sk::Device& device, uint32_t& imageIndex)
+{
+ const auto& vk = app.vulkan.vk;
+
+ VkResult r = VK_SUCCESS;
+
+ // Wait until we can start rendering the next frame
+ if ((r = vk.waitForFence(
+ device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame])) ||
+ (r = vk.resetFence(
+ device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame]))) {
+ return r;
+ }
+
+ // Rebuild the renderer first if the window size has changed
+ if (app.extent.width != app.renderer.swapchain.extent.width ||
+ app.extent.height != app.renderer.swapchain.extent.height) {
+ if ((r = recreateRenderer(
+ app, vk, app.gpu, app.extent, app.rectData, app.rectShaders))) {
+ return r;
+ }
+ }
+
+ // Acquire the next image to render, rebuilding if necessary
+ while ((r = vk.acquireNextImageKHR(
+ device,
+ app.renderer.swapchain.swapchain,
+ UINT64_MAX,
+ app.renderer.sync.imageAvailable[app.renderer.sync.currentFrame],
+ {},
+ &imageIndex))) {
+ switch (r) {
+ case VK_SUBOPTIMAL_KHR:
+ case VK_ERROR_OUT_OF_DATE_KHR:
+ if ((r = recreateRenderer(app,
+ vk,
+ app.gpu,
+ app.renderer.swapchain.extent,
+ app.rectData,
+ app.rectShaders))) {
+ return r;
+ }
+ continue;
+ default:
+ return r;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+void
+update(PuglVulkanDemo& app, const double time)
+{
+ // Animate rectangles
+ for (size_t i = 0; i < app.rects.size(); ++i) {
+ moveRect(&app.rects[i],
+ i,
+ app.rects.size(),
+ static_cast<float>(app.extent.width),
+ static_cast<float>(app.extent.height),
+ time);
+ }
+
+ // Update vertex buffer
+ memcpy(app.rectData.vertexData.get(),
+ app.rects.data(),
+ sizeof(Rect) * app.rects.size());
+
+ // Update uniform buffer
+ UniformBufferObject ubo = {{}};
+ mat4Ortho(ubo.projection,
+ 0.0f,
+ float(app.renderer.swapchain.extent.width),
+ 0.0f,
+ float(app.renderer.swapchain.extent.height),
+ -1.0f,
+ 1.0f);
+
+ memcpy(app.rectData.uniformData.get(), &ubo, sizeof(ubo));
+}
+
+VkResult
+endFrame(const sk::VulkanApi& vk,
+ const GraphicsDevice& gpu,
+ const Renderer& renderer,
+ const uint32_t imageIndex)
+{
+ const auto currentFrame = renderer.sync.currentFrame;
+ VkResult r = VK_SUCCESS;
+
+ static constexpr VkPipelineStageFlags waitStage =
+ VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ const VkSubmitInfo submitInfo{
+ VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ nullptr,
+ SK_COUNTED(1, &renderer.sync.imageAvailable[currentFrame].get()),
+ &waitStage,
+ SK_COUNTED(1, &renderer.renderPass.commandBuffers[imageIndex]),
+ SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get())};
+
+ if ((r = vk.queueSubmit(gpu.graphicsQueue,
+ submitInfo,
+ renderer.sync.inFlight[currentFrame]))) {
+ return r;
+ }
+
+ const VkPresentInfoKHR presentInfo{
+ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ nullptr,
+ SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get()),
+ SK_COUNTED(1, &renderer.swapchain.swapchain.get(), &imageIndex),
+ nullptr};
+
+ switch ((r = vk.queuePresentKHR(gpu.graphicsQueue, presentInfo))) {
+ case VK_SUCCESS: // Sucessfully presented
+ case VK_SUBOPTIMAL_KHR: // Probably a resize race, ignore
+ case VK_ERROR_OUT_OF_DATE_KHR: // Probably a resize race, ignore
+ break;
+ default:
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+pugl::Status
+View::onEvent(const pugl::ExposeEvent&)
+{
+ const auto& vk = _app.vulkan.vk;
+ const auto& gpu = _app.gpu;
+
+ // Acquire the next image, waiting and/or rebuilding if necessary
+ auto nextImageIndex = 0u;
+ if (beginFrame(_app, gpu.device, nextImageIndex)) {
+ return pugl::Status::unknownError;
+ }
+
+ // Ready to go, update the data to the current time
+ update(_app, world().time());
+
+ // Submit the frame to the queue and present it
+ endFrame(vk, gpu, _app.renderer, nextImageIndex);
+
+ ++_app.framesDrawn;
+ ++_app.renderer.sync.currentFrame;
+ _app.renderer.sync.currentFrame %= _app.renderer.sync.inFlight.size();
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+View::onEvent(const pugl::LoopEnterEvent&)
+{
+ _app.resizing = true;
+ startTimer(resizeTimerId,
+ 1.0 / static_cast<double>(getHint(pugl::ViewHint::refreshRate)));
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+View::onEvent(const pugl::TimerEvent&)
+{
+ return postRedisplay();
+}
+
+pugl::Status
+View::onEvent(const pugl::LoopLeaveEvent&)
+{
+ stopTimer(resizeTimerId);
+
+ // Trigger a swapchain recreation with the normal present mode
+ _app.renderer.swapchain.extent = {};
+ _app.resizing = false;
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+View::onEvent(const pugl::KeyPressEvent& event)
+{
+ if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') {
+ _app.quit = true;
+ }
+
+ return pugl::Status::success;
+}
+
+pugl::Status
+View::onEvent(const pugl::CloseEvent&)
+{
+ _app.quit = true;
+
+ return pugl::Status::success;
+}
+
+VkResult
+VulkanContext::init(pugl::VulkanLoader& loader, const PuglTestOptions& opts)
+{
+ VkResult r = VK_SUCCESS;
+
+ sk::VulkanInitApi initApi{};
+
+ // Load Vulkan API and set up the fundamentals
+ if ((r = initApi.init(loader.getInstanceProcAddrFunc())) ||
+ (r = createInstance(initApi, opts, instance)) ||
+ (r = vk.init(initApi, instance)) ||
+ (r = getDebugReportCallback(vk, instance, opts.verbose, debugCallback))) {
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+int
+run(const char* const programPath,
+ const PuglTestOptions opts,
+ const size_t numRects)
+{
+ PuglVulkanDemo app{programPath, opts, numRects};
+
+ VkResult r = VK_SUCCESS;
+ const auto width = static_cast<int>(app.extent.width);
+ const auto height = static_cast<int>(app.extent.height);
+
+ // Realize window so we can set up Vulkan
+ app.world.setClassName("PuglVulkanDemo");
+ app.view.setWindowTitle("Pugl Vulkan Demo");
+ app.view.setAspectRatio(1, 1, 16, 9);
+ app.view.setDefaultSize(width, height);
+ app.view.setMinSize(width / 4, height / 4);
+ app.view.setMaxSize(width * 4, height * 4);
+ app.view.setBackend(pugl::vulkanBackend());
+ app.view.setHint(pugl::ViewHint::resizable, opts.resizable);
+ const pugl::Status st = app.view.realize();
+ if (st != pugl::Status::success) {
+ return logError("Failed to create window (%s)\n", pugl::strerror(st));
+ }
+
+ if (!app.loader) {
+ return logError("Failed to load Vulkan library\n");
+ }
+
+ // Load Vulkan for the view
+ if ((r = app.vulkan.init(app.loader, opts))) {
+ return logError("Failed to set up Vulkan API (%s)\n", sk::string(r));
+ }
+
+ const auto& vk = app.vulkan.vk;
+
+ // Set up the graphics device
+ if ((r = app.gpu.init(app.loader, app.vulkan, app.view, opts))) {
+ return logError("Failed to set up device (%s)\n", sk::string(r));
+ }
+
+ logInfo("Present mode", sk::string(app.gpu.presentMode));
+ logInfo("Resize present mode", sk::string(app.gpu.resizePresentMode));
+
+ // Set up the rectangle data we will render every frame
+ if ((r = app.rectData.init(vk, app.gpu, app.rects.size()))) {
+ return logError("Failed to allocate render data (%s)\n", sk::string(r));
+ }
+
+ // Load shader modules
+ if ((r = app.rectShaders.init(vk, app.gpu, app.programPath))) {
+ return logError("Failed to load shaders (%s)\n", sk::string(r));
+ }
+
+ if ((r = app.renderer.init(app.vulkan.vk,
+ app.gpu,
+ app.rectData,
+ app.rectShaders,
+ app.extent,
+ false))) {
+ return logError("Failed to create renderer (%s)\n", sk::string(r));
+ }
+
+ logInfo("Swapchain frames",
+ std::to_string(app.renderer.swapchain.imageViews.size()));
+ logInfo("Frames in flight",
+ std::to_string(app.renderer.sync.inFlight.size()));
+
+ recordCommandBuffers(app.vulkan.vk,
+ app.renderer.swapchain,
+ app.renderer.renderPass,
+ app.renderer.rectPipeline,
+ app.rectData);
+
+ const int refreshRate = app.view.getHint(pugl::ViewHint::refreshRate);
+ const double frameDuration = 1.0 / static_cast<double>(refreshRate);
+ const double timeout = app.opts.sync ? frameDuration : 0.0;
+
+ PuglFpsPrinter fpsPrinter = {app.world.time()};
+ app.view.show();
+ while (!app.quit) {
+ app.world.update(timeout);
+ puglPrintFps(app.world.cobj(), &fpsPrinter, &app.framesDrawn);
+ }
+
+ if ((r = app.vulkan.vk.deviceWaitIdle(app.gpu.device))) {
+ return logError("Failed to wait for device idle (%s)\n", sk::string(r));
+ }
+
+ return 0;
+}
+
+} // namespace
+
+int
+main(int argc, char** argv)
+{
+ // Parse command line options
+ const char* const programPath = argv[0];
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage(programPath, "");
+ return 0;
+ }
+
+ // Parse number of rectangles argument, if given
+ int64_t numRects = 1000;
+ if (argc >= 1) {
+ char* endptr = nullptr;
+ numRects = strtol(argv[0], &endptr, 10);
+ if (endptr != argv[0] + strlen(argv[0]) || numRects < 1) {
+ logError("Invalid number of rectangles: %s\n", argv[0]);
+ return 1;
+ }
+ }
+
+ // Run application
+ return run(programPath, opts, static_cast<size_t>(numRects));
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_vulkan_demo.c b/subprojects/d2tk/pugl/examples/pugl_vulkan_demo.c
new file mode 100644
index 0000000..0dfbadd
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_vulkan_demo.c
@@ -0,0 +1,1127 @@
+/*
+ Copyright 2019-2020 David Robillard <d@drobilla.net>
+ Copyright 2019 Jordan Halase <jordan@halase.me>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ A simple example of drawing with Vulkan.
+
+ For a more advanced demo that actually draws something interesting, see
+ pugl_vulkan_cxx_demo.cpp.
+*/
+
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/pugl.h"
+#include "pugl/vulkan.h"
+
+#include <vulkan/vk_platform.h>
+#include <vulkan/vulkan_core.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CLAMP(x, l, h) ((x) <= (l) ? (l) : (x) >= (h) ? (h) : (x))
+
+// Vulkan allocation callbacks which can be used for debugging
+#define ALLOC_VK NULL
+
+// Helper macro for allocating arrays by type, with C++ compatible cast
+#define AALLOC(size, Type) ((Type*)calloc(size, sizeof(Type)))
+
+// Helper macro for counted array arguments to make clang-format behave
+#define COUNTED(count, ...) count, __VA_ARGS__
+
+/// Dynamically loaded Vulkan API functions
+typedef struct {
+ PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
+ PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
+} InstanceAPI;
+
+/// Vulkan swapchain and everything that depends on it
+typedef struct {
+ VkSwapchainKHR rawSwapchain;
+ uint32_t nImages;
+ VkExtent2D extent;
+ VkImage* images;
+ VkImageView* imageViews;
+ VkFence* fences;
+ VkCommandBuffer* commandBuffers;
+} Swapchain;
+
+/// Synchronization semaphores
+typedef struct {
+ VkSemaphore presentComplete;
+ VkSemaphore renderFinished;
+} Sync;
+
+/// Vulkan state, purely Vulkan functions can depend on only this
+typedef struct {
+ InstanceAPI api;
+ VkInstance instance;
+ VkDebugReportCallbackEXT debugCallback;
+ VkSurfaceKHR surface;
+ VkSurfaceFormatKHR surfaceFormat;
+ VkPresentModeKHR presentMode;
+ VkPhysicalDeviceProperties deviceProperties;
+ VkPhysicalDevice physicalDevice;
+ uint32_t graphicsIndex;
+ VkDevice device;
+ VkQueue graphicsQueue;
+ VkCommandPool commandPool;
+ Swapchain* swapchain;
+ Sync sync;
+} VulkanState;
+
+/// Complete application
+typedef struct {
+ PuglTestOptions opts;
+ PuglWorld* world;
+ PuglView* view;
+ VulkanState vk;
+ uint32_t framesDrawn;
+ uint32_t width;
+ uint32_t height;
+ bool quit;
+} VulkanApp;
+
+static VKAPI_ATTR VkBool32 VKAPI_CALL
+debugCallback(VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objType,
+ uint64_t obj,
+ size_t location,
+ int32_t code,
+ const char* layerPrefix,
+ const char* msg,
+ void* userData)
+{
+ (void)userData;
+ (void)objType;
+ (void)obj;
+ (void)location;
+ (void)code;
+
+ if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
+ fprintf(stderr, "note: ");
+ } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
+ fprintf(stderr, "warning: ");
+ } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
+ fprintf(stderr, "performance warning: ");
+ } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
+ fprintf(stderr, "error: ");
+ } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
+ fprintf(stderr, "debug: ");
+ }
+
+ fprintf(stderr, "%s: ", layerPrefix);
+ fprintf(stderr, "%s\n", msg);
+ return VK_FALSE;
+}
+
+static bool
+hasExtension(const char* const name,
+ const VkExtensionProperties* const properties,
+ const uint32_t count)
+{
+ for (uint32_t i = 0; i < count; ++i) {
+ if (!strcmp(properties[i].extensionName, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+hasLayer(const char* const name,
+ const VkLayerProperties* const properties,
+ const uint32_t count)
+{
+ for (uint32_t i = 0; i < count; ++i) {
+ if (!strcmp(properties[i].layerName, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void
+pushString(const char*** const array,
+ uint32_t* const count,
+ const char* const string)
+{
+ *array = (const char**)realloc(*array, (*count + 1) * sizeof(const char*));
+ (*array)[*count] = string;
+ ++*count;
+}
+
+static VkResult
+createInstance(VulkanApp* const app)
+{
+ const VkApplicationInfo appInfo = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ NULL,
+ "Pugl Vulkan Test",
+ VK_MAKE_VERSION(0, 1, 0),
+ "Pugl Vulkan Test Engine",
+ VK_MAKE_VERSION(0, 1, 0),
+ VK_MAKE_VERSION(1, 0, 0),
+ };
+
+ // Get the number of supported extensions and layers
+ VkResult vr = VK_SUCCESS;
+ uint32_t nExtProps = 0;
+ uint32_t nLayerProps = 0;
+ if ((vr = vkEnumerateInstanceLayerProperties(&nLayerProps, NULL)) ||
+ (vr = vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, NULL))) {
+ return vr;
+ }
+
+ // Get properties of supported extensions
+ VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties);
+ vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, extProps);
+
+ uint32_t nExtensions = 0;
+ const char** extensions = NULL;
+
+ // Add extensions required by pugl
+ uint32_t nPuglExts = 0;
+ const char* const* puglExts = puglGetInstanceExtensions(&nPuglExts);
+ for (uint32_t i = 0; i < nPuglExts; ++i) {
+ pushString(&extensions, &nExtensions, puglExts[i]);
+ }
+
+ // Add extra extensions we want to use if they are supported
+ if (hasExtension("VK_EXT_debug_report", extProps, nExtProps)) {
+ pushString(&extensions, &nExtensions, "VK_EXT_debug_report");
+ }
+
+ // Get properties of supported layers
+ VkLayerProperties* layerProps = AALLOC(nLayerProps, VkLayerProperties);
+ vkEnumerateInstanceLayerProperties(&nLayerProps, layerProps);
+
+ // Add validation layers if error checking is enabled
+ uint32_t nLayers = 0;
+ const char** layers = NULL;
+ if (app->opts.errorChecking) {
+ const char* debugLayers[] = {"VK_LAYER_KHRONOS_validation",
+ "VK_LAYER_LUNARG_standard_validation",
+ NULL};
+
+ for (const char** l = debugLayers; *l; ++l) {
+ if (hasLayer(*l, layerProps, nLayerProps)) {
+ pushString(&layers, &nLayers, *l);
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < nExtensions; ++i) {
+ printf("Using instance extension: %s\n", extensions[i]);
+ }
+
+ for (uint32_t i = 0; i < nLayers; ++i) {
+ printf("Using instance layer: %s\n", layers[i]);
+ }
+
+ const VkInstanceCreateInfo createInfo = {
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ NULL,
+ 0,
+ &appInfo,
+ COUNTED(nLayers, layers),
+ COUNTED(nExtensions, extensions),
+ };
+
+ if ((vr = vkCreateInstance(&createInfo, ALLOC_VK, &app->vk.instance))) {
+ logError("Could not create Vulkan Instance: %d\n", vr);
+ }
+
+ free(layers);
+ free(extensions);
+ free(layerProps);
+ free(extProps);
+
+ return vr;
+}
+
+static VkResult
+enableDebugging(VulkanState* const vk)
+{
+ vk->api.vkCreateDebugReportCallbackEXT =
+ (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
+ vk->instance, "vkCreateDebugReportCallbackEXT");
+
+ vk->api.vkDestroyDebugReportCallbackEXT =
+ (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
+ vk->instance, "vkDestroyDebugReportCallbackEXT");
+
+ if (vk->api.vkCreateDebugReportCallbackEXT) {
+ const VkDebugReportCallbackCreateInfoEXT info = {
+ VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
+ NULL,
+ VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
+ debugCallback,
+ NULL,
+ };
+
+ VkResult vr = VK_SUCCESS;
+ if ((vr = vk->api.vkCreateDebugReportCallbackEXT(
+ vk->instance, &info, ALLOC_VK, &vk->debugCallback))) {
+ logError("Could not create debug reporter: %d\n", vr);
+ return vr;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
+static VkResult
+getGraphicsQueueIndex(VkSurfaceKHR surface,
+ VkPhysicalDevice device,
+ uint32_t* graphicsIndex)
+{
+ VkResult r = VK_SUCCESS;
+
+ uint32_t nProps = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, NULL);
+
+ VkQueueFamilyProperties* props = AALLOC(nProps, VkQueueFamilyProperties);
+ vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, props);
+
+ for (uint32_t q = 0; q < nProps; ++q) {
+ if (props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ VkBool32 supported = false;
+ if ((r = vkGetPhysicalDeviceSurfaceSupportKHR(
+ device, q, surface, &supported))) {
+ free(props);
+ return r;
+ }
+
+ if (supported) {
+ *graphicsIndex = q;
+ free(props);
+ return VK_SUCCESS;
+ }
+ }
+ }
+
+ free(props);
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+}
+
+static bool
+supportsRequiredExtensions(const VkPhysicalDevice device)
+{
+ uint32_t nExtProps = 0;
+ vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, NULL);
+
+ VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties);
+ vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, extProps);
+
+ for (uint32_t i = 0; i < nExtProps; ++i) {
+ if (!strcmp(extProps[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+ free(extProps);
+ return true;
+ }
+ }
+
+ free(extProps);
+ return false;
+}
+
+static bool
+isDeviceSuitable(const VulkanState* const vk,
+ const VkPhysicalDevice device,
+ uint32_t* const graphicsIndex)
+{
+ if (!supportsRequiredExtensions(device) ||
+ getGraphicsQueueIndex(vk->surface, device, graphicsIndex)) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ Selects a physical graphics device.
+
+ This doesn't try to be clever, and just selects the first suitable device.
+*/
+static VkResult
+selectPhysicalDevice(VulkanState* const vk)
+{
+ VkResult vr = VK_SUCCESS;
+ if (!vk->surface) {
+ logError("Cannot select a physical device without a surface\n");
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ uint32_t nDevices = 0;
+ if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) {
+ logError("Failed to get count of physical devices: %d\n", vr);
+ return vr;
+ }
+
+ if (!nDevices) {
+ logError("No physical devices found\n");
+ return VK_ERROR_DEVICE_LOST;
+ }
+
+ VkPhysicalDevice* devices = AALLOC(nDevices, VkPhysicalDevice);
+ if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) {
+ logError("Failed to enumerate physical devices: %d\n", vr);
+ free(devices);
+ return vr;
+ }
+
+ uint32_t i = 0;
+ for (i = 0; i < nDevices; ++i) {
+ VkPhysicalDeviceProperties deviceProps = {0};
+ vkGetPhysicalDeviceProperties(devices[i], &deviceProps);
+
+ uint32_t graphicsIndex = 0;
+ if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) {
+ printf("Using device %u/%u: \"%s\"\n",
+ i + 1,
+ nDevices,
+ deviceProps.deviceName);
+ vk->deviceProperties = deviceProps;
+ vk->physicalDevice = devices[i];
+ vk->graphicsIndex = graphicsIndex;
+ printf("Using graphics queue family: %u\n", vk->graphicsIndex);
+ break;
+ }
+
+ printf("Device \"%s\" not suitable\n", deviceProps.deviceName);
+ }
+
+ if (i >= nDevices) {
+ logError("No suitable devices found\n");
+ vr = VK_ERROR_DEVICE_LOST;
+ }
+
+ free(devices);
+ return vr;
+}
+
+/// Opens the logical device and sets up the queue and command pool
+static VkResult
+openDevice(VulkanState* const vk)
+{
+ if (vk->device) {
+ logError("Renderer already has an opened device\n");
+ return VK_NOT_READY;
+ }
+
+ const float graphicsQueuePriority = 1.0f;
+ const char* const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
+
+ const VkDeviceQueueCreateInfo queueCreateInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ NULL,
+ 0,
+ vk->graphicsIndex,
+ COUNTED(1, &graphicsQueuePriority),
+ };
+
+ const VkDeviceCreateInfo createInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ NULL,
+ 0,
+ COUNTED(1, &queueCreateInfo),
+ COUNTED(0, NULL),
+ COUNTED(1, &swapchainName),
+ NULL,
+ };
+
+ VkDevice device = NULL;
+ VkResult vr = VK_SUCCESS;
+ if ((vr =
+ vkCreateDevice(vk->physicalDevice, &createInfo, ALLOC_VK, &device))) {
+ logError("Could not open device \"%s\": %d\n",
+ vk->deviceProperties.deviceName,
+ vr);
+ return vr;
+ }
+
+ vk->device = device;
+ vkGetDeviceQueue(vk->device, vk->graphicsIndex, 0, &vk->graphicsQueue);
+
+ const VkCommandPoolCreateInfo commandInfo = {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ NULL,
+ 0,
+ vk->graphicsIndex,
+ };
+
+ if ((vr = vkCreateCommandPool(
+ vk->device, &commandInfo, ALLOC_VK, &vk->commandPool))) {
+ logError("Could not create command pool: %d\n", vr);
+ return vr;
+ }
+
+ return VK_SUCCESS;
+}
+
+static const char*
+presentModeString(const VkPresentModeKHR presentMode)
+{
+ switch (presentMode) {
+ case VK_PRESENT_MODE_IMMEDIATE_KHR:
+ return "Immediate";
+ case VK_PRESENT_MODE_MAILBOX_KHR:
+ return "Mailbox";
+ case VK_PRESENT_MODE_FIFO_KHR:
+ return "FIFO";
+ case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
+ return "FIFO relaxed";
+ default:
+ return "Other";
+ }
+}
+
+static bool
+hasPresentMode(const VkPresentModeKHR mode,
+ const VkPresentModeKHR* const presentModes,
+ const uint32_t nPresentModes)
+{
+ for (uint32_t i = 0; i < nPresentModes; ++i) {
+ if (presentModes[i] == mode) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/// Configure the surface for the currently opened device
+static VkResult
+configureSurface(VulkanState* const vk)
+{
+ uint32_t nFormats = 0;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(
+ vk->physicalDevice, vk->surface, &nFormats, NULL);
+ if (!nFormats) {
+ logError("No surface formats available\n");
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ VkSurfaceFormatKHR* surfaceFormats = AALLOC(nFormats, VkSurfaceFormatKHR);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(
+ vk->physicalDevice, vk->surface, &nFormats, surfaceFormats);
+
+ const VkSurfaceFormatKHR want = {VK_FORMAT_B8G8R8A8_UNORM,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
+
+ uint32_t formatIndex = 0;
+ for (formatIndex = 0; formatIndex < nFormats; ++formatIndex) {
+ if (surfaceFormats[formatIndex].format == want.format &&
+ surfaceFormats[formatIndex].colorSpace == want.colorSpace) {
+ vk->surfaceFormat = want;
+ break;
+ }
+ }
+ free(surfaceFormats);
+ if (formatIndex >= nFormats) {
+ logError("Could not find a suitable surface format\n");
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ uint32_t nPresentModes = 0;
+ vkGetPhysicalDeviceSurfacePresentModesKHR(
+ vk->physicalDevice, vk->surface, &nPresentModes, NULL);
+ if (!nPresentModes) {
+ logError("No present modes available\n");
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ VkPresentModeKHR* presentModes = AALLOC(nPresentModes, VkPresentModeKHR);
+ vkGetPhysicalDeviceSurfacePresentModesKHR(
+ vk->physicalDevice, vk->surface, &nPresentModes, presentModes);
+
+ const VkPresentModeKHR tryModes[] = {
+ VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+ VK_PRESENT_MODE_FIFO_KHR,
+ VK_PRESENT_MODE_IMMEDIATE_KHR,
+ };
+
+ VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ for (uint32_t i = 0; i < sizeof(tryModes) / sizeof(VkPresentModeKHR); ++i) {
+ if (hasPresentMode(tryModes[i], presentModes, nPresentModes)) {
+ presentMode = tryModes[i];
+ break;
+ }
+ }
+
+ free(presentModes);
+ vk->presentMode = presentMode;
+ printf("Using present mode: \"%s\" (%u)\n",
+ presentModeString(presentMode),
+ presentMode);
+
+ return VK_SUCCESS;
+}
+
+static VkResult
+createRawSwapchain(VulkanState* const vk,
+ const uint32_t width,
+ const uint32_t height)
+{
+ VkSurfaceCapabilitiesKHR surfaceCapabilities;
+ VkResult vr = VK_SUCCESS;
+ if ((vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ vk->physicalDevice, vk->surface, &surfaceCapabilities))) {
+ logError("Could not get surface capabilities: %d\n", vr);
+ return vr;
+ }
+
+ /* There is a known race condition with window/surface sizes, so we clamp
+ to what Vulkan reports and hope for the best. */
+
+ vk->swapchain->extent.width = CLAMP(width,
+ surfaceCapabilities.minImageExtent.width,
+ surfaceCapabilities.maxImageExtent.width);
+
+ vk->swapchain->extent.height =
+ CLAMP(height,
+ surfaceCapabilities.minImageExtent.height,
+ surfaceCapabilities.maxImageExtent.height);
+
+ vk->swapchain->nImages = surfaceCapabilities.minImageCount;
+
+ const VkSwapchainCreateInfoKHR createInfo = {
+ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ NULL,
+ 0,
+ vk->surface,
+ vk->swapchain->nImages,
+ vk->surfaceFormat.format,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+ vk->swapchain->extent,
+ 1,
+ (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT),
+ VK_SHARING_MODE_EXCLUSIVE,
+ COUNTED(0, NULL),
+ surfaceCapabilities.currentTransform,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ vk->presentMode,
+ VK_TRUE,
+ 0,
+ };
+
+ if ((vr = vkCreateSwapchainKHR(
+ vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) {
+ logError("Could not create swapchain: %d\n", vr);
+ return vr;
+ }
+
+ return VK_SUCCESS;
+}
+
+static VkResult
+recordCommandBuffers(VulkanState* const vk)
+{
+ const VkClearColorValue clearValue = {{
+ 0xA4 / (float)0x100, // R
+ 0x1E / (float)0x100, // G
+ 0x22 / (float)0x100, // B
+ 0xFF / (float)0x100, // A
+ }};
+
+ const VkImageSubresourceRange range = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0,
+ 1,
+ 0,
+ 1,
+ };
+
+ const VkCommandBufferBeginInfo beginInfo = {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ NULL,
+ VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
+ NULL,
+ };
+
+ for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) {
+ const VkImageMemoryBarrier toClearBarrier = {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ NULL,
+ VK_ACCESS_MEMORY_READ_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ vk->graphicsIndex,
+ vk->graphicsIndex,
+ vk->swapchain->images[i],
+ range,
+ };
+
+ const VkImageMemoryBarrier toPresentBarrier = {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ NULL,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_ACCESS_MEMORY_READ_BIT,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ vk->graphicsIndex,
+ vk->graphicsIndex,
+ vk->swapchain->images[i],
+ range,
+ };
+
+ vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo);
+
+ vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i],
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0,
+ COUNTED(0, NULL),
+ COUNTED(0, NULL),
+ COUNTED(1, &toClearBarrier));
+
+ vkCmdClearColorImage(vk->swapchain->commandBuffers[i],
+ vk->swapchain->images[i],
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ &clearValue,
+ COUNTED(1, &range));
+
+ vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i],
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ 0,
+ COUNTED(0, NULL),
+ COUNTED(0, NULL),
+ COUNTED(1, &toPresentBarrier));
+
+ vkEndCommandBuffer(vk->swapchain->commandBuffers[i]);
+ }
+
+ return VK_SUCCESS;
+}
+
+static VkResult
+createSwapchain(VulkanState* const vk,
+ const uint32_t width,
+ const uint32_t height)
+{
+ VkResult vr = VK_SUCCESS;
+
+ vk->swapchain = AALLOC(1, Swapchain);
+ if ((vr = createRawSwapchain(vk, width, height))) {
+ return vr;
+ }
+
+ if ((vr = vkGetSwapchainImagesKHR(vk->device,
+ vk->swapchain->rawSwapchain,
+ &vk->swapchain->nImages,
+ NULL))) {
+ logError("Failed to query swapchain images: %d\n", vr);
+ return vr;
+ }
+
+ vk->swapchain->images = AALLOC(vk->swapchain->nImages, VkImage);
+ if ((vr = vkGetSwapchainImagesKHR(vk->device,
+ vk->swapchain->rawSwapchain,
+ &vk->swapchain->nImages,
+ vk->swapchain->images))) {
+ logError("Failed to get swapchain images: %d\n", vr);
+ return vr;
+ }
+
+ const VkCommandBufferAllocateInfo allocInfo = {
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ NULL,
+ vk->commandPool,
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ vk->swapchain->nImages,
+ };
+
+ vk->swapchain->commandBuffers =
+ AALLOC(vk->swapchain->nImages, VkCommandBuffer);
+
+ if ((vr = vkAllocateCommandBuffers(
+ vk->device, &allocInfo, vk->swapchain->commandBuffers))) {
+ logError("Could not allocate command buffers: %d\n", vr);
+ return vr;
+ }
+
+ const VkFenceCreateInfo fenceInfo = {
+ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+ NULL,
+ VK_FENCE_CREATE_SIGNALED_BIT,
+ };
+ vk->swapchain->fences = AALLOC(vk->swapchain->nImages, VkFence);
+
+ for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) {
+ if ((vr = vkCreateFence(
+ vk->device, &fenceInfo, ALLOC_VK, &vk->swapchain->fences[i]))) {
+ logError("Could not create render finished fence: %d\n", vr);
+ return vr;
+ }
+ }
+
+ if ((vr = recordCommandBuffers(vk))) {
+ logError("Failed to record command buffers\n");
+ return vr;
+ }
+
+ return VK_SUCCESS;
+}
+
+static void
+destroySwapchain(VulkanState* const vk, Swapchain* const swapchain)
+{
+ if (!swapchain) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < swapchain->nImages; ++i) {
+ if (swapchain->fences[i]) {
+ vkDestroyFence(vk->device, swapchain->fences[i], ALLOC_VK);
+ }
+
+ if (swapchain->imageViews && swapchain->imageViews[i]) {
+ vkDestroyImageView(vk->device, swapchain->imageViews[i], ALLOC_VK);
+ }
+ }
+
+ free(swapchain->fences);
+ swapchain->fences = NULL;
+ free(swapchain->imageViews);
+ swapchain->imageViews = NULL;
+
+ if (swapchain->images) {
+ free(swapchain->images);
+ swapchain->images = NULL;
+ }
+
+ if (swapchain->commandBuffers) {
+ vkFreeCommandBuffers(vk->device,
+ vk->commandPool,
+ swapchain->nImages,
+ swapchain->commandBuffers);
+ free(swapchain->commandBuffers);
+ }
+
+ if (swapchain->rawSwapchain) {
+ vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK);
+ }
+
+ free(swapchain);
+}
+
+static VkResult
+createSyncObjects(VulkanState* const vk)
+{
+ const VkSemaphoreCreateInfo info = {
+ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ NULL,
+ 0,
+ };
+
+ vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.presentComplete);
+ vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.renderFinished);
+ return VK_SUCCESS;
+}
+
+static void
+destroySyncObjects(VulkanState* const vk)
+{
+ if (vk->sync.renderFinished) {
+ vkDestroySemaphore(vk->device, vk->sync.renderFinished, ALLOC_VK);
+ vk->sync.renderFinished = VK_NULL_HANDLE;
+ }
+ if (vk->sync.presentComplete) {
+ vkDestroySemaphore(vk->device, vk->sync.presentComplete, ALLOC_VK);
+ vk->sync.presentComplete = VK_NULL_HANDLE;
+ }
+}
+
+static void
+closeDevice(VulkanState* const vk)
+{
+ if (vk->device) {
+ vkDeviceWaitIdle(vk->device);
+ destroySyncObjects(vk);
+ destroySwapchain(vk, vk->swapchain);
+ if (vk->commandPool) {
+ vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK);
+ vk->commandPool = VK_NULL_HANDLE;
+ }
+ vk->graphicsQueue = VK_NULL_HANDLE;
+ vkDestroyDevice(vk->device, ALLOC_VK);
+ vk->device = VK_NULL_HANDLE;
+ }
+}
+
+static void
+destroyWorld(VulkanApp* const app)
+{
+ VulkanState* vk = &app->vk;
+
+ if (vk) {
+ closeDevice(vk);
+
+ if (app->view) {
+ puglHide(app->view);
+ puglFreeView(app->view);
+ app->view = NULL;
+ }
+ if (vk->debugCallback && vk->api.vkDestroyDebugReportCallbackEXT) {
+ vk->api.vkDestroyDebugReportCallbackEXT(
+ vk->instance, vk->debugCallback, ALLOC_VK);
+ vk->debugCallback = VK_NULL_HANDLE;
+ }
+ if (vk->surface) {
+ vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK);
+ vk->surface = VK_NULL_HANDLE;
+ }
+ if (vk->instance) {
+ fflush(stderr);
+ vkDestroyInstance(vk->instance, ALLOC_VK);
+ vk->instance = VK_NULL_HANDLE;
+ }
+ if (app->world) {
+ puglFreeWorld(app->world);
+ app->world = NULL;
+ }
+ }
+}
+
+static PuglStatus
+onConfigure(PuglView* const view, const double width, const double height)
+{
+ VulkanApp* const app = (VulkanApp*)puglGetHandle(view);
+
+ // We just record the size here and lazily resize the surface when exposed
+ app->width = (uint32_t)width;
+ app->height = (uint32_t)height;
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+recreateSwapchain(VulkanState* const vk,
+ const uint32_t width,
+ const uint32_t height)
+{
+ vkDeviceWaitIdle(vk->device);
+ destroySwapchain(vk, vk->swapchain);
+
+ if (createSwapchain(vk, width, height)) {
+ logError("Failed to recreate swapchain\n");
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+onExpose(PuglView* const view)
+{
+ VulkanApp* app = (VulkanApp*)puglGetHandle(view);
+ VulkanState* vk = &app->vk;
+ uint32_t imageIndex = 0;
+ VkResult result = VK_SUCCESS;
+
+ // Recreate swapchain if the window size has changed
+ const Swapchain* swapchain = vk->swapchain;
+ if (swapchain->extent.width != app->width ||
+ swapchain->extent.height != app->height) {
+ recreateSwapchain(vk, app->width, app->height);
+ }
+
+ // Acquire the next image to render, rebuilding if necessary
+ while ((result = vkAcquireNextImageKHR(vk->device,
+ vk->swapchain->rawSwapchain,
+ UINT64_MAX,
+ vk->sync.presentComplete,
+ VK_NULL_HANDLE,
+ &imageIndex))) {
+ switch (result) {
+ case VK_SUCCESS:
+ break;
+ case VK_SUBOPTIMAL_KHR:
+ case VK_ERROR_OUT_OF_DATE_KHR:
+ recreateSwapchain(vk, app->width, app->height);
+ continue;
+ default:
+ logError("Could not acquire swapchain image: %d\n", result);
+ return PUGL_UNKNOWN_ERROR;
+ }
+ }
+
+ // Wait until we can start rendering this frame
+ vkWaitForFences(vk->device,
+ COUNTED(1, &vk->swapchain->fences[imageIndex]),
+ VK_TRUE,
+ UINT64_MAX);
+ vkResetFences(vk->device, 1, &vk->swapchain->fences[imageIndex]);
+
+ const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ // Submit command buffer to render this frame
+ const VkSubmitInfo submitInfo = {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ NULL,
+ COUNTED(1, &vk->sync.presentComplete),
+ &waitStage,
+ COUNTED(1, &vk->swapchain->commandBuffers[imageIndex]),
+ COUNTED(1, &vk->sync.renderFinished)};
+ if ((result = vkQueueSubmit(vk->graphicsQueue,
+ 1,
+ &submitInfo,
+ vk->swapchain->fences[imageIndex]))) {
+ logError("Could not submit to queue: %d\n", result);
+ return PUGL_FAILURE;
+ }
+
+ // Present this frame
+ const VkPresentInfoKHR presentInfo = {
+ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ NULL,
+ COUNTED(1, &vk->sync.renderFinished),
+ COUNTED(1, &vk->swapchain->rawSwapchain, &imageIndex, NULL),
+ };
+ if ((result = vkQueuePresentKHR(vk->graphicsQueue, &presentInfo))) {
+ logError("Could not present image: %d\n", result);
+ }
+
+ if (app->opts.continuous) {
+ ++app->framesDrawn;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+onEvent(PuglView* const view, const PuglEvent* const e)
+{
+ VulkanApp* const app = (VulkanApp*)puglGetHandle(view);
+
+ printEvent(e, "Event: ", app->opts.verbose);
+
+ switch (e->type) {
+ case PUGL_EXPOSE:
+ return onExpose(view);
+ case PUGL_CONFIGURE:
+ return onConfigure(view, e->configure.width, e->configure.height);
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ case PUGL_KEY_PRESS:
+ switch (e->key.key) {
+ case PUGL_KEY_ESCAPE:
+ case 'q':
+ app->quit = 1;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return PUGL_SUCCESS;
+}
+
+int
+main(int argc, char** argv)
+{
+ VulkanApp app = {0};
+ VulkanState* vk = &app.vk;
+ const uint32_t defaultWidth = 640;
+ const uint32_t defaultHeight = 360;
+ const PuglRect frame = {0, 0, defaultWidth, defaultHeight};
+
+ // Parse command line options
+ app.opts = puglParseTestOptions(&argc, &argv);
+ if (app.opts.help) {
+ puglPrintTestUsage(argv[0], "");
+ return 0;
+ }
+
+ // Create world and view
+ if (!(app.world = puglNewWorld(PUGL_PROGRAM, PUGL_WORLD_THREADS))) {
+ return logError("Failed to create world\n");
+ }
+
+ if (!(app.view = puglNewView(app.world))) {
+ puglFreeWorld(app.world);
+ return logError("Failed to create Pugl World and View\n");
+ }
+
+ // Create Vulkan instance
+ if (createInstance(&app)) {
+ puglFreeWorld(app.world);
+ return logError("Failed to create instance\n");
+ }
+
+ // Create window
+ puglSetWindowTitle(app.view, "Pugl Vulkan");
+ puglSetFrame(app.view, frame);
+ puglSetHandle(app.view, &app);
+ puglSetBackend(app.view, puglVulkanBackend());
+ puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable);
+ puglSetEventFunc(app.view, onEvent);
+ const PuglStatus st = puglRealize(app.view);
+ if (st) {
+ puglFreeWorld(app.world);
+ puglFreeView(app.view);
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ // Create Vulkan surface for Window
+ PuglVulkanLoader* loader = puglNewVulkanLoader(app.world);
+ if (puglCreateSurface(puglGetInstanceProcAddrFunc(loader),
+ app.view,
+ vk->instance,
+ ALLOC_VK,
+ &vk->surface)) {
+ return logError("Failed to create surface\n");
+ }
+
+ // Set up Vulkan
+ VkResult vr = VK_SUCCESS;
+ if ((vr = enableDebugging(vk)) || //
+ (vr = selectPhysicalDevice(vk)) || //
+ (vr = openDevice(vk)) || //
+ (vr = configureSurface(vk)) || //
+ (vr = createSwapchain(vk, defaultWidth, defaultHeight)) || //
+ (vr = createSyncObjects(vk))) {
+ destroyWorld(&app);
+ return logError("Failed to set up graphics (%d)\n", vr);
+ }
+
+ printf("Swapchain images: %u\n", app.vk.swapchain->nImages);
+
+ PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
+ puglShow(app.view);
+ while (!app.quit) {
+ puglUpdate(app.world, -1.0);
+
+ if (app.opts.continuous) {
+ puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn);
+ }
+ }
+
+ destroyWorld(&app);
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/pugl_window_demo.c b/subprojects/d2tk/pugl/examples/pugl_window_demo.c
new file mode 100644
index 0000000..f7d5b2c
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_window_demo.c
@@ -0,0 +1,254 @@
+/*
+ Copyright 2012-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ A demonstration of using multiple top-level windows.
+*/
+
+#include "cube_view.h"
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+
+#include <math.h>
+#include <stdbool.h>
+#include <string.h>
+
+typedef struct {
+ PuglView* view;
+ double xAngle;
+ double yAngle;
+ double lastMouseX;
+ double lastMouseY;
+ double lastDrawTime;
+ float dist;
+ bool entered;
+} CubeView;
+
+typedef struct {
+ PuglWorld* world;
+ CubeView cubes[2];
+ int quit;
+ bool continuous;
+ bool verbose;
+} PuglTestApp;
+
+static const double pad = 64.0;
+
+static void
+onDisplay(PuglView* view)
+{
+ PuglWorld* world = puglGetWorld(view);
+ PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world);
+ CubeView* cube = (CubeView*)puglGetHandle(view);
+
+ const double thisTime = puglGetTime(app->world);
+ if (app->continuous) {
+ const double dTime = thisTime - cube->lastDrawTime;
+
+ cube->xAngle = fmod(cube->xAngle + dTime * 100.0, 360.0);
+ cube->yAngle = fmod(cube->yAngle + dTime * 100.0, 360.0);
+ }
+
+ displayCube(
+ view, cube->dist, (float)cube->xAngle, (float)cube->yAngle, cube->entered);
+
+ cube->lastDrawTime = thisTime;
+}
+
+static void
+onKeyPress(PuglView* view, const PuglEventKey* event)
+{
+ PuglWorld* world = puglGetWorld(view);
+ PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world);
+ PuglRect frame = puglGetFrame(view);
+
+ if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) {
+ app->quit = 1;
+ } else if (event->state & PUGL_MOD_SHIFT) {
+ if (event->key == PUGL_KEY_UP) {
+ frame.height += 10;
+ } else if (event->key == PUGL_KEY_DOWN) {
+ frame.height -= 10;
+ } else if (event->key == PUGL_KEY_LEFT) {
+ frame.width -= 10;
+ } else if (event->key == PUGL_KEY_RIGHT) {
+ frame.width += 10;
+ } else {
+ return;
+ }
+ puglSetFrame(view, frame);
+ } else {
+ if (event->key == PUGL_KEY_UP) {
+ frame.y -= 10;
+ } else if (event->key == PUGL_KEY_DOWN) {
+ frame.y += 10;
+ } else if (event->key == PUGL_KEY_LEFT) {
+ frame.x -= 10;
+ } else if (event->key == PUGL_KEY_RIGHT) {
+ frame.x += 10;
+ } else {
+ return;
+ }
+ puglSetFrame(view, frame);
+ }
+}
+
+static void
+redisplayView(PuglTestApp* app, PuglView* view)
+{
+ if (!app->continuous) {
+ puglPostRedisplay(view);
+ }
+}
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglWorld* world = puglGetWorld(view);
+ PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world);
+ CubeView* cube = (CubeView*)puglGetHandle(view);
+
+ const char* const prefix = cube == &app->cubes[0] ? "View 1: " : "View 2: ";
+ printEvent(event, prefix, app->verbose);
+
+ switch (event->type) {
+ case PUGL_CONFIGURE:
+ reshapeCube((float)event->configure.width, (float)event->configure.height);
+ break;
+ case PUGL_UPDATE:
+ if (app->continuous) {
+ puglPostRedisplay(view);
+ }
+ break;
+ case PUGL_EXPOSE:
+ onDisplay(view);
+ break;
+ case PUGL_CLOSE:
+ app->quit = 1;
+ break;
+ case PUGL_KEY_PRESS:
+ onKeyPress(view, &event->key);
+ break;
+ case PUGL_MOTION:
+ cube->xAngle -= event->motion.x - cube->lastMouseX;
+ cube->yAngle += event->motion.y - cube->lastMouseY;
+ cube->lastMouseX = event->motion.x;
+ cube->lastMouseY = event->motion.y;
+ redisplayView(app, view);
+ break;
+ case PUGL_SCROLL:
+ cube->dist = fmaxf(10.0f, cube->dist + (float)event->scroll.dy);
+ redisplayView(app, view);
+ break;
+ case PUGL_POINTER_IN:
+ cube->entered = true;
+ redisplayView(app, view);
+ break;
+ case PUGL_POINTER_OUT:
+ cube->entered = false;
+ redisplayView(app, view);
+ break;
+ case PUGL_FOCUS_IN:
+ case PUGL_FOCUS_OUT:
+ redisplayView(app, view);
+ break;
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTestApp app = {0};
+
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage(argv[0], "");
+ return 1;
+ }
+
+ app.continuous = opts.continuous;
+ app.verbose = opts.verbose;
+
+ app.world = puglNewWorld(PUGL_PROGRAM, 0);
+ app.cubes[0].view = puglNewView(app.world);
+ app.cubes[1].view = puglNewView(app.world);
+
+ puglSetWorldHandle(app.world, &app);
+ puglSetClassName(app.world, "Pugl Test");
+
+ PuglStatus st = PUGL_SUCCESS;
+ for (unsigned i = 0; i < 2; ++i) {
+ CubeView* cube = &app.cubes[i];
+ PuglView* view = cube->view;
+ const PuglRect frame = {
+ pad + (128.0 + pad) * i, pad + (128.0 + pad) * i, 512.0, 512.0};
+
+ cube->dist = 10;
+
+ puglSetWindowTitle(view, "Pugl Window Demo");
+ puglSetFrame(view, frame);
+ puglSetDefaultSize(view, 512, 512);
+ puglSetMinSize(view, 128, 128);
+ puglSetMaxSize(view, 2048, 2048);
+ puglSetBackend(view, puglGlBackend());
+
+ puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking);
+ puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable);
+ puglSetViewHint(view, PUGL_SAMPLES, opts.samples);
+ puglSetViewHint(view, PUGL_DOUBLE_BUFFER, opts.doubleBuffer);
+ puglSetViewHint(view, PUGL_SWAP_INTERVAL, opts.sync);
+ puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat);
+ puglSetHandle(view, cube);
+ puglSetEventFunc(view, onEvent);
+
+ if (i == 1) {
+ puglSetTransientFor(app.cubes[1].view,
+ puglGetNativeWindow(app.cubes[0].view));
+ }
+
+ if ((st = puglRealize(view))) {
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ puglShow(view);
+ }
+
+ PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
+ unsigned framesDrawn = 0;
+ while (!app.quit) {
+ puglUpdate(app.world, app.continuous ? 0.0 : -1.0);
+ ++framesDrawn;
+
+ if (app.continuous) {
+ puglPrintFps(app.world, &fpsPrinter, &framesDrawn);
+ }
+ }
+
+ for (size_t i = 0; i < 2; ++i) {
+ puglFreeView(app.cubes[i].view);
+ }
+
+ puglFreeWorld(app.world);
+
+ return 0;
+}
diff --git a/subprojects/d2tk/pugl/examples/rects.h b/subprojects/d2tk/pugl/examples/rects.h
new file mode 100644
index 0000000..b99d9f0
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/rects.h
@@ -0,0 +1,79 @@
+/*
+ Copyright 2019-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef EXAMPLES_RECTS_H
+#define EXAMPLES_RECTS_H
+
+#include <math.h>
+#include <stddef.h>
+
+typedef float vec2[2];
+
+typedef struct {
+ float pos[2];
+ float size[2];
+ float fillColor[4];
+} Rect;
+
+static const vec2 rectVertices[] = {
+ {0.0f, 0.0f}, // TL
+ {1.0f, 0.0f}, // TR
+ {0.0f, 1.0f}, // BL
+ {1.0f, 1.0f} // BR
+};
+
+static const unsigned rectIndices[4] = {0, 1, 2, 3};
+
+/// Make a new rectangle with the given index (each is slightly different)
+static inline Rect
+makeRect(const size_t index, const float frameWidth)
+{
+ static const float alpha = 0.3f;
+ const float minSize = frameWidth / 64.0f;
+ const float maxSize = frameWidth / 6.0f;
+ const float s = (sinf((float)index) / 2.0f + 0.5f);
+ const float c = (cosf((float)index) / 2.0f + 0.5f);
+
+ const Rect rect = {
+ {0.0f, 0.0f}, // Position is set later during expose
+ {minSize + s * maxSize, minSize + c * maxSize},
+ {0.0f, s / 2.0f + 0.25f, c / 2.0f + 0.25f, alpha},
+ };
+
+ return rect;
+}
+
+/// Move `rect` with the given index around in an arbitrary way that looks cool
+static inline void
+moveRect(Rect* const rect,
+ const size_t index,
+ const size_t numRects,
+ const float frameWidth,
+ const float frameHeight,
+ const double time)
+{
+ const float normal = (float)index / (float)numRects;
+ const float offset[2] = {normal * 128.0f, normal * 128.0f};
+
+ rect->pos[0] = (frameWidth - rect->size[0] + offset[0]) *
+ (sinf((float)time * rect->size[0] / 64.0f + normal) + 1.0f) /
+ 2.0f;
+ rect->pos[1] = (frameHeight - rect->size[1] + offset[1]) *
+ (cosf((float)time * rect->size[1] / 64.0f + normal) + 1.0f) /
+ 2.0f;
+}
+
+#endif // EXAMPLES_RECTS_H
diff --git a/subprojects/d2tk/pugl/examples/shader_utils.h b/subprojects/d2tk/pugl/examples/shader_utils.h
new file mode 100644
index 0000000..2575f47
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shader_utils.h
@@ -0,0 +1,106 @@
+/*
+ Copyright 2019-2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef EXAMPLES_SHADER_UTILS_H
+#define EXAMPLES_SHADER_UTILS_H
+
+#include "glad/glad.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ GLuint vertexShader;
+ GLuint fragmentShader;
+ GLuint program;
+} Program;
+
+static GLuint
+compileShader(const char* header, const char* source, const GLenum type)
+{
+ const GLchar* sources[] = {header, source};
+ const GLint lengths[] = {(GLint)strlen(header), (GLint)strlen(source)};
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 2, sources, lengths);
+ glCompileShader(shader);
+
+ int status = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (status == GL_FALSE) {
+ GLint length = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
+
+ char* log = (char*)calloc(1, (size_t)length);
+ glGetShaderInfoLog(shader, length, &length, log);
+ fprintf(stderr, "error: Failed to compile shader (%s)\n", log);
+ free(log);
+
+ return 0;
+ }
+
+ return shader;
+}
+
+static void
+deleteProgram(Program program)
+{
+ glDeleteShader(program.vertexShader);
+ glDeleteShader(program.fragmentShader);
+ glDeleteProgram(program.program);
+}
+
+static Program
+compileProgram(const char* headerSource,
+ const char* vertexSource,
+ const char* fragmentSource)
+{
+ static const Program nullProgram = {0, 0, 0};
+
+ Program program = {
+ compileShader(headerSource, vertexSource, GL_VERTEX_SHADER),
+ compileShader(headerSource, fragmentSource, GL_FRAGMENT_SHADER),
+ glCreateProgram(),
+ };
+
+ if (!program.vertexShader || !program.fragmentShader || !program.program) {
+ deleteProgram(program);
+ return nullProgram;
+ }
+
+ glAttachShader(program.program, program.vertexShader);
+ glAttachShader(program.program, program.fragmentShader);
+ glLinkProgram(program.program);
+
+ GLint status = 0;
+ glGetProgramiv(program.program, GL_LINK_STATUS, &status);
+ if (status == GL_FALSE) {
+ GLint length = 0;
+ glGetProgramiv(program.program, GL_INFO_LOG_LENGTH, &length);
+
+ char* log = (char*)calloc(1, (size_t)length);
+ glGetProgramInfoLog(program.program, length, &length, &log[0]);
+ fprintf(stderr, "error: Failed to link program (%s)\n", log);
+ free(log);
+
+ deleteProgram(program);
+ return nullProgram;
+ }
+
+ return program;
+}
+
+#endif // EXAMPLES_SHADER_UTILS_H
diff --git a/subprojects/d2tk/pugl/examples/shaders/header_330.glsl b/subprojects/d2tk/pugl/examples/shaders/header_330.glsl
new file mode 100644
index 0000000..59d5f6f
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shaders/header_330.glsl
@@ -0,0 +1,4 @@
+#version 330 core
+
+#define INTER(qualifiers)
+#define UBO(qualifiers) layout(std140)
diff --git a/subprojects/d2tk/pugl/examples/shaders/header_420.glsl b/subprojects/d2tk/pugl/examples/shaders/header_420.glsl
new file mode 100644
index 0000000..2beaad0
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shaders/header_420.glsl
@@ -0,0 +1,4 @@
+#version 420 core
+
+#define INTER(qualifiers) layout(qualifiers)
+#define UBO(qualifiers) layout(std140, qualifiers)
diff --git a/subprojects/d2tk/pugl/examples/shaders/meson.build b/subprojects/d2tk/pugl/examples/shaders/meson.build
new file mode 100644
index 0000000..e47be9d
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shaders/meson.build
@@ -0,0 +1,35 @@
+shader_files = [
+ 'header_330.glsl',
+ 'header_420.glsl',
+ 'rect.frag',
+ 'rect.vert',
+]
+
+# Copy shader sources for GL examples
+foreach shader_file : shader_files
+ configure_file(copy: true, input: shader_file, output: shader_file)
+endforeach
+
+# Build SPV shader binaries for Vulkan examples
+if vulkan_dep.found()
+ cat = find_program('../../scripts/cat.py')
+ glslang = find_program('glslangValidator')
+
+ shaders = ['rect.vert', 'rect.frag']
+ foreach shader : shaders
+ source = shader.split('.')[0] + '.vulkan.' + shader.split('.')[1]
+ shader_input = custom_target(source,
+ output: source,
+ input: ['header_420.glsl', shader],
+ command: [cat, '@INPUT@'],
+ build_by_default: true,
+ capture: true)
+
+ mytarget = custom_target(shader,
+ output: shader + '.spv',
+ input: shader_input,
+ command: [glslang, '-V', '-o', '@OUTPUT@', '@INPUT@'],
+ build_by_default: true,
+ install: false)
+ endforeach
+endif
diff --git a/subprojects/d2tk/pugl/examples/shaders/rect.frag b/subprojects/d2tk/pugl/examples/shaders/rect.frag
new file mode 100644
index 0000000..33bfbb2
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shaders/rect.frag
@@ -0,0 +1,33 @@
+/* The fragment shader uses the UV coordinates to calculate whether it is in
+ the T, R, B, or L border. These are then mixed with the border color, and
+ their inverse is mixed with the fill color, to calculate the fragment color.
+ For example, if we are in the top border, then T=1, so the border mix factor
+ TRBL=1, and the fill mix factor (1-TRBL) is 0.
+
+ The use of pixel units here is handy because the border width can be
+ specified precisely in pixels to draw sharp lines. The border width is just
+ hardcoded, but could be made a uniform or vertex attribute easily enough. */
+
+INTER(location = 0) noperspective in vec2 f_uv;
+INTER(location = 1) noperspective in vec2 f_size;
+INTER(location = 2) noperspective in vec4 f_fillColor;
+
+layout(location = 0) out vec4 FragColor;
+
+void
+main()
+{
+ const float borderWidth = 2.0;
+
+ vec4 borderColor = f_fillColor + vec4(0.0, 0.4, 0.4, 0.0);
+ float t = step(borderWidth, f_uv[1]);
+ float r = step(borderWidth, f_size.x - f_uv[0]);
+ float b = step(borderWidth, f_size.y - f_uv[1]);
+ float l = step(borderWidth, f_uv[0]);
+ float fillMix = t * r * b * l;
+ float borderMix = 1.0 - fillMix;
+ vec4 fill = fillMix * f_fillColor;
+ vec4 border = borderMix * borderColor;
+
+ FragColor = fill + border;
+}
diff --git a/subprojects/d2tk/pugl/examples/shaders/rect.vert b/subprojects/d2tk/pugl/examples/shaders/rect.vert
new file mode 100644
index 0000000..2c7b5f1
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shaders/rect.vert
@@ -0,0 +1,36 @@
+/* The vertex shader is trivial, but forwards scaled UV coordinates (in pixels)
+ to the fragment shader for drawing the border. */
+
+UBO(binding = 0) uniform UniformBufferObject
+{
+ mat4 projection;
+}
+ubo;
+
+layout(location = 0) in vec2 v_position;
+layout(location = 1) in vec2 v_origin;
+layout(location = 2) in vec2 v_size;
+layout(location = 3) in vec4 v_fillColor;
+
+INTER(location = 0) noperspective out vec2 f_uv;
+INTER(location = 1) noperspective out vec2 f_size;
+INTER(location = 2) noperspective out vec4 f_fillColor;
+
+void
+main()
+{
+ // clang-format off
+ mat4 m = mat4(v_size[0], 0.0, 0.0, 0.0,
+ 0.0, v_size[1], 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ v_origin[0], v_origin[1], 0.0, 1.0);
+ // clang-format on
+
+ mat4 MVP = ubo.projection * m;
+
+ f_uv = v_position * v_size;
+ f_size = v_size;
+ f_fillColor = v_fillColor;
+
+ gl_Position = MVP * vec4(v_position, 0.0, 1.0);
+}
diff --git a/subprojects/d2tk/pugl/examples/sybok.hpp b/subprojects/d2tk/pugl/examples/sybok.hpp
new file mode 100644
index 0000000..7740824
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/sybok.hpp
@@ -0,0 +1,2325 @@
+/*
+ Copyright 2020 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file sybok.hpp
+ @brief A minimal C++ wrapper for the Vulkan API.
+
+ This is a manually-written minimal wrapper for Vulkan. It makes working
+ with Vulkan a little easier in C++, but takes a different approach than
+ vulkan.hpp. In particular:
+
+ - Works nicely with dynamic loading. Since the API itself is an object, it
+ is simple to ensure the dynamically loaded API (or a consistent API in
+ general) is used everywhere. Passing a dispatch parameter to every
+ function as in vulkan.hpp makes dynamic loading extremely painful (not to
+ mention ugly), and mistakes tend to become link time errors. This is, in
+ my opinion, a glaring design flaw, and the real reason why this wrapper
+ reluctantly exists.
+
+ - Explicit separation of the initial API that does not require an instance
+ to load, from the rest of the API that does.
+
+ - Opinionated use of scoped handles everywhere.
+
+ - Remains close to the C API so that code can be easily ported. This means
+ that the pattern of return codes with output parameters is preserved,
+ except with smart handles that make leaks impossible. While less pretty,
+ this does not require exceptions.
+
+ - No exceptions or RTTI required.
+
+ - A safe scoped API for commands that encodes the semantics of the Vulkan
+ API. For example, it is statically impossible to call render scope
+ commands while not in a render scope.
+
+ - A reasonable amount of relatively readable code.
+
+ On the other hand, there are far fewer niceties, and the C API is used
+ directly as much as possible, particularly for structs (although they are
+ taken by const reference so they can be written inline). There is only
+ support for a minimal portable subset of Vulkan 1.1 with a few portable KHR
+ extensions.
+
+ In short, if the above sounds appealing, or you want a minimal wrapper that
+ can be extended if necessary to suit your application, you might find this
+ useful. If you want a fully-featured wrapper for Vulkan and don't care
+ about linker dependencies, you probably won't.
+*/
+
+#ifndef SYBOK_HPP
+#define SYBOK_HPP
+
+#ifdef VULKAN_CORE_H_
+# error "sybok.hpp must be included before or instead of vulkan headers"
+#endif
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wswitch-enum"
+#endif
+
+#define VK_NO_PROTOTYPES
+
+// On 64-bit platforms, all handles are "dispatchable" pointers
+#if defined(__LP64__) || defined(_WIN64) || \
+ (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \
+ defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \
+ defined(__powerpc64__)
+
+# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \
+ typedef struct object##_T* object; // NOLINT(bugprone-macro-parentheses)
+
+// On 32-bit platforms, some "non-dispatchable" handles are 64 bit integers
+#else
+
+/// Trivial wrapper class for a 64-bit integer handle for type safety
+template<class Tag>
+struct NonDispatchableHandle {
+ explicit operator uint64_t() const noexcept { return handle; }
+ explicit operator bool() const noexcept { return handle; }
+
+ uint64_t handle;
+};
+
+# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \
+ using object = NonDispatchableHandle<struct Sk##object##Tag>;
+
+#endif
+
+#include <vulkan/vulkan_core.h> // IWYU pragma: export
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+#include <utility>
+
+#if __cplusplus >= 201703L
+# define SYBOK_NODISCARD [[nodiscard]]
+#elif defined(__GNUC__)
+# define SYBOK_NODISCARD [[gnu::warn_unused_result]]
+#else
+# define SYBOK_NODISCARD
+#endif
+
+/// Helper macro to make array arguments format nicely
+#define SK_COUNTED(count, ...) count, __VA_ARGS__
+
+namespace sk {
+
+class CommandScope;
+class RenderCommandScope;
+
+inline const char*
+string(const VkResult result)
+{
+ switch (result) {
+ case VK_SUCCESS:
+ return "Success";
+ case VK_NOT_READY:
+ return "Not Ready";
+ case VK_TIMEOUT:
+ return "Timeout";
+ case VK_EVENT_SET:
+ return "Event set";
+ case VK_EVENT_RESET:
+ return "Event reset";
+ case VK_INCOMPLETE:
+ return "Incomplete";
+ case VK_ERROR_OUT_OF_HOST_MEMORY:
+ return "Out of host memory";
+ case VK_ERROR_OUT_OF_DEVICE_MEMORY:
+ return "Out of device memory";
+ case VK_ERROR_INITIALIZATION_FAILED:
+ return "Initialization failed";
+ case VK_ERROR_DEVICE_LOST:
+ return "Device lost";
+ case VK_ERROR_MEMORY_MAP_FAILED:
+ return "Memory map failed";
+ case VK_ERROR_LAYER_NOT_PRESENT:
+ return "Layer not present";
+ case VK_ERROR_EXTENSION_NOT_PRESENT:
+ return "Extension not present";
+ case VK_ERROR_FEATURE_NOT_PRESENT:
+ return "Feature not present";
+ case VK_ERROR_INCOMPATIBLE_DRIVER:
+ return "Incompatible driver";
+ case VK_ERROR_TOO_MANY_OBJECTS:
+ return "Too many objects";
+ case VK_ERROR_FORMAT_NOT_SUPPORTED:
+ return "Format not supported";
+ case VK_ERROR_FRAGMENTED_POOL:
+ return "Fragmented pool";
+ case VK_ERROR_OUT_OF_POOL_MEMORY: // Vulkan 1.1
+ return "Out of pool memory";
+ case VK_ERROR_INVALID_EXTERNAL_HANDLE: // Vulkan 1.1
+ return "Invalid external handle";
+ case VK_ERROR_SURFACE_LOST_KHR: // VK_KHR_surface
+ return "Surface lost";
+ case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: // VK_KHR_surface
+ return "Native window in use";
+ case VK_SUBOPTIMAL_KHR: // VK_KHR_swapchain
+ return "Suboptimal";
+ case VK_ERROR_OUT_OF_DATE_KHR: // VK_KHR_swapchain
+ return "Out of date";
+ case VK_ERROR_VALIDATION_FAILED_EXT: // VK_EXT_debug_report
+ return "Validation failed";
+ default:
+ break;
+ }
+
+ return "Unknown error";
+}
+
+inline const char*
+string(const VkPresentModeKHR presentMode)
+{
+ switch (presentMode) {
+ case VK_PRESENT_MODE_IMMEDIATE_KHR:
+ return "Immediate";
+ case VK_PRESENT_MODE_MAILBOX_KHR:
+ return "Mailbox";
+ case VK_PRESENT_MODE_FIFO_KHR:
+ return "FIFO";
+ case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
+ return "Relaxed FIFO";
+ default:
+ break;
+ }
+
+ return "Unknown present mode";
+}
+
+inline const char*
+string(const VkDebugReportFlagBitsEXT flag)
+{
+ switch (flag) {
+ case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
+ return "Information";
+ case VK_DEBUG_REPORT_WARNING_BIT_EXT:
+ return "Warning";
+ case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
+ return "Performance Warning";
+ case VK_DEBUG_REPORT_ERROR_BIT_EXT:
+ return "Error";
+ case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
+ return "Debug";
+ default:
+ break;
+ }
+
+ return "Unknown report";
+}
+
+template<class T>
+class GlobalDeleter
+{
+public:
+ using DestroyFunc = void (*)(T, const VkAllocationCallbacks*);
+
+ GlobalDeleter() = default;
+ ~GlobalDeleter() = default;
+
+ // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
+ GlobalDeleter(DestroyFunc destroyFunc) noexcept
+ : _destroyFunc{destroyFunc}
+ {}
+
+ GlobalDeleter(const GlobalDeleter&) = delete;
+ GlobalDeleter& operator=(const GlobalDeleter&) = delete;
+
+ GlobalDeleter(GlobalDeleter&& other) noexcept
+ {
+ std::swap(_destroyFunc, other._destroyFunc);
+ }
+
+ GlobalDeleter& operator=(GlobalDeleter&& other) noexcept
+ {
+ std::swap(_destroyFunc, other._destroyFunc);
+ return *this;
+ }
+
+ void operator()(T handle) noexcept
+ {
+ if (_destroyFunc && handle) {
+ _destroyFunc(handle, nullptr);
+ }
+ }
+
+private:
+ DestroyFunc _destroyFunc{};
+};
+
+template<class T, class Parent>
+class DependantDeleter
+{
+public:
+ using DestroyFunc = void (*)(Parent, T, const VkAllocationCallbacks*);
+
+ DependantDeleter() = default;
+ ~DependantDeleter() = default;
+
+ DependantDeleter(Parent parent, DestroyFunc destroyFunc) noexcept
+ : _parent{parent}
+ , _destroyFunc{destroyFunc}
+ {}
+
+ DependantDeleter(const DependantDeleter&) = delete;
+ DependantDeleter& operator=(const DependantDeleter&) = delete;
+
+ DependantDeleter(DependantDeleter&& other) noexcept { swap(other); }
+
+ DependantDeleter& operator=(DependantDeleter&& other) noexcept
+ {
+ swap(other);
+ return *this;
+ }
+
+ void operator()(T handle) noexcept
+ {
+ if (_parent && _destroyFunc && handle) {
+ _destroyFunc(_parent, handle, nullptr);
+ }
+ }
+
+private:
+ void swap(DependantDeleter& other) noexcept
+ {
+ std::swap(_parent, other._parent);
+ std::swap(_destroyFunc, other._destroyFunc);
+ }
+
+ Parent _parent{};
+ DestroyFunc _destroyFunc{};
+};
+
+template<class T, class Pool, class FreeFuncResult>
+class PoolDeleter
+{
+public:
+ using FreeFunc = FreeFuncResult (*)(VkDevice, Pool, uint32_t, const T*);
+
+ PoolDeleter() noexcept = default;
+ ~PoolDeleter() noexcept = default;
+
+ PoolDeleter(VkDevice device,
+ Pool pool,
+ uint32_t count,
+ FreeFunc freeFunc) noexcept
+ : _device{device}
+ , _pool{pool}
+ , _count{count}
+ , _freeFunc{freeFunc}
+ {}
+
+ PoolDeleter(const PoolDeleter&) = delete;
+ PoolDeleter& operator=(const PoolDeleter&) = delete;
+
+ PoolDeleter(PoolDeleter&& other) noexcept { swap(other); }
+
+ PoolDeleter& operator=(PoolDeleter&& other) noexcept
+ {
+ swap(other);
+ return *this;
+ }
+
+ void operator()(T* handle) noexcept
+ {
+ if (_device && _pool && handle) {
+ _freeFunc(_device, _pool, _count, handle);
+ }
+ }
+
+private:
+ void swap(PoolDeleter& other) noexcept
+ {
+ std::swap(_device, other._device);
+ std::swap(_pool, other._pool);
+ std::swap(_count, other._count);
+ std::swap(_freeFunc, other._freeFunc);
+ }
+
+ VkDevice _device{};
+ Pool _pool{};
+ uint32_t _count{};
+ FreeFunc _freeFunc{};
+};
+
+template<class T, class TDeleter>
+class UniqueDispatchableHandle
+{
+public:
+ using Deleter = TDeleter;
+ using Handle = T;
+
+ static_assert(std::is_pointer<T>::value, "");
+
+ UniqueDispatchableHandle() = default;
+
+ UniqueDispatchableHandle(Handle handle, Deleter deleter) noexcept
+ : _handle{handle}
+ , _deleter{std::move(deleter)}
+ {}
+
+ ~UniqueDispatchableHandle() noexcept
+ {
+ if (_handle) {
+ _deleter(_handle);
+ }
+ }
+
+ UniqueDispatchableHandle(const UniqueDispatchableHandle&) noexcept = delete;
+ UniqueDispatchableHandle& operator =(
+ const UniqueDispatchableHandle&) noexcept = delete;
+
+ UniqueDispatchableHandle(UniqueDispatchableHandle&& other) noexcept
+ {
+ swap(other);
+ }
+
+ UniqueDispatchableHandle& operator=(UniqueDispatchableHandle&& other) noexcept
+ {
+ swap(other);
+ return *this;
+ }
+
+ const Handle& get() const noexcept { return _handle; }
+
+ // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
+ operator Handle() const noexcept { return _handle; }
+
+private:
+ void swap(UniqueDispatchableHandle& other) noexcept
+ {
+ std::swap(_handle, other._handle);
+ std::swap(_deleter, other._deleter);
+ }
+
+ Handle _handle{};
+ Deleter _deleter{};
+};
+
+#if defined(__LP64__) || defined(_WIN64) || \
+ (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \
+ defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \
+ defined(__powerpc64__)
+
+template<class T, class TDeleter>
+using UniqueNonDispatchableHandle = UniqueDispatchableHandle<T, TDeleter>;
+
+#else
+
+template<class T, class TDeleter>
+class UniqueNonDispatchableHandle
+{
+public:
+ using Deleter = TDeleter;
+ using Handle = T;
+
+ UniqueNonDispatchableHandle() = default;
+
+ UniqueNonDispatchableHandle(T handle, Deleter deleter) noexcept
+ : _handle{handle}
+ , _deleter{std::move(deleter)}
+ {
+ assert(handle);
+ }
+
+ ~UniqueNonDispatchableHandle() noexcept
+ {
+ if (_handle) {
+ _deleter(_handle);
+ }
+ }
+
+ UniqueNonDispatchableHandle(const UniqueNonDispatchableHandle&) noexcept =
+ delete;
+ UniqueNonDispatchableHandle& operator =(
+ const UniqueNonDispatchableHandle&) noexcept = delete;
+
+ UniqueNonDispatchableHandle(UniqueNonDispatchableHandle&& other) noexcept
+ {
+ swap(other);
+ }
+
+ UniqueNonDispatchableHandle& operator=(
+ UniqueNonDispatchableHandle&& other) noexcept
+ {
+ swap(other);
+ return *this;
+ }
+
+ const Handle& get() const noexcept { return _handle; }
+
+ operator Handle() const noexcept { return _handle; }
+
+private:
+ void swap(UniqueNonDispatchableHandle& other) noexcept
+ {
+ std::swap(_handle, other._handle);
+ std::swap(_deleter, other._deleter);
+ }
+
+ T _handle{};
+ Deleter _deleter{};
+};
+
+#endif
+
+template<class Vector, class Deleter>
+class UniqueArrayHandle
+{
+public:
+ using T = typename Vector::value_type;
+
+ UniqueArrayHandle() = default;
+
+ UniqueArrayHandle(uint32_t size, Vector&& array, Deleter deleter) noexcept
+ : _array{std::move(array)}
+ , _deleter{std::move(deleter)}
+ , _size{size}
+ {
+ assert(!_array.empty());
+ }
+
+ ~UniqueArrayHandle() noexcept
+ {
+ if (!_array.empty()) {
+ _deleter(_array.data());
+ }
+ }
+
+ UniqueArrayHandle(const UniqueArrayHandle&) noexcept = delete;
+ UniqueArrayHandle& operator=(const UniqueArrayHandle&) noexcept = delete;
+
+ UniqueArrayHandle(UniqueArrayHandle&& other) noexcept { swap(other); }
+
+ UniqueArrayHandle& operator=(UniqueArrayHandle&& other) noexcept
+ {
+ swap(other);
+ return *this;
+ }
+
+ const T& operator[](const size_t index) const noexcept
+ {
+ return _array[index];
+ }
+
+ T& operator[](const size_t index) noexcept { return _array[index]; }
+
+ const T* get() const noexcept { return _array.data(); }
+ T* get() noexcept { return _array.data(); }
+
+private:
+ void swap(UniqueArrayHandle& other) noexcept
+ {
+ std::swap(_array, other._array);
+ std::swap(_deleter, other._deleter);
+ std::swap(_size, other._size);
+ }
+
+ Vector _array{};
+ Deleter _deleter{};
+ uint32_t _size{};
+};
+
+template<typename T>
+class OptionalParameter
+{
+public:
+ using Handle = typename T::Handle;
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions, google-explicit-constructor)
+ OptionalParameter(const T& value) noexcept
+ : _handle{value.get()}
+ {}
+
+ OptionalParameter() noexcept = default;
+ ~OptionalParameter() noexcept = default;
+
+ OptionalParameter(const OptionalParameter&) = delete;
+ OptionalParameter& operator=(const OptionalParameter&) = delete;
+
+ OptionalParameter(OptionalParameter&&) = delete;
+ OptionalParameter& operator=(OptionalParameter&&) = delete;
+
+ Handle get() const noexcept { return _handle; }
+
+private:
+ Handle _handle{};
+};
+
+template<typename T>
+using GlobalObject = UniqueDispatchableHandle<T, GlobalDeleter<T>>;
+
+template<typename T>
+using InstanceChild =
+ UniqueNonDispatchableHandle<T, DependantDeleter<T, VkInstance>>;
+
+template<typename T>
+using DispatchableDeviceChild =
+ UniqueDispatchableHandle<T, DependantDeleter<T, VkDevice>>;
+
+template<typename T>
+using NonDispatchableDeviceChild =
+ UniqueNonDispatchableHandle<T, DependantDeleter<T, VkDevice>>;
+
+template<typename Vector, typename Pool, typename FreeFuncResult>
+using PoolChild = UniqueArrayHandle<
+ Vector,
+ PoolDeleter<typename Vector::value_type, Pool, FreeFuncResult>>;
+
+using Device = GlobalObject<VkDevice>;
+using Instance = GlobalObject<VkInstance>;
+
+using PhysicalDevice = VkPhysicalDevice; // Weak handle, no destroy function
+using Queue = VkQueue; // Weak handle, no destroy function
+
+using Buffer = NonDispatchableDeviceChild<VkBuffer>;
+using BufferView = NonDispatchableDeviceChild<VkBufferView>;
+using CommandBuffer = DispatchableDeviceChild<VkCommandBuffer>;
+using CommandPool = NonDispatchableDeviceChild<VkCommandPool>;
+using DescriptorPool = NonDispatchableDeviceChild<VkDescriptorPool>;
+using DescriptorSetLayout = NonDispatchableDeviceChild<VkDescriptorSetLayout>;
+using DeviceMemory = NonDispatchableDeviceChild<VkDeviceMemory>;
+using Event = NonDispatchableDeviceChild<VkEvent>;
+using Fence = NonDispatchableDeviceChild<VkFence>;
+using Framebuffer = NonDispatchableDeviceChild<VkFramebuffer>;
+using Image = NonDispatchableDeviceChild<VkImage>;
+using ImageView = NonDispatchableDeviceChild<VkImageView>;
+using Pipeline = NonDispatchableDeviceChild<VkPipeline>;
+using PipelineCache = NonDispatchableDeviceChild<VkPipelineCache>;
+using PipelineLayout = NonDispatchableDeviceChild<VkPipelineLayout>;
+using QueryPool = NonDispatchableDeviceChild<VkQueryPool>;
+using RenderPass = NonDispatchableDeviceChild<VkRenderPass>;
+using Sampler = NonDispatchableDeviceChild<VkSampler>;
+using Semaphore = NonDispatchableDeviceChild<VkSemaphore>;
+using ShaderModule = NonDispatchableDeviceChild<VkShaderModule>;
+
+template<class VkCommandBufferVector>
+using CommandBuffers = PoolChild<VkCommandBufferVector, VkCommandPool, void>;
+
+template<class VkDescriptorSetVector>
+using DescriptorSets =
+ PoolChild<VkDescriptorSetVector, VkDescriptorPool, VkResult>;
+
+// VK_KHR_swapchain
+using SwapchainKHR = NonDispatchableDeviceChild<VkSwapchainKHR>;
+
+// VK_KHR_surface
+using SurfaceKHR = InstanceChild<VkSurfaceKHR>;
+
+// VK_EXT_debug_report
+using DebugReportCallbackEXT = InstanceChild<VkDebugReportCallbackEXT>;
+
+template<size_t...>
+struct IndexSequence {};
+
+template<size_t N, size_t... Next>
+struct IndexSequenceHelper
+ : public IndexSequenceHelper<N - 1U, N - 1U, Next...> {};
+
+template<size_t... Next>
+struct IndexSequenceHelper<0U, Next...> {
+ using type = IndexSequence<Next...>;
+};
+
+template<size_t N>
+using makeIndexSequence = typename IndexSequenceHelper<N>::type;
+
+template<class T, class Parent, class DestroyFunc, size_t count, size_t... Is>
+std::array<T, count>
+make_handle_array_h(Parent parent,
+ DestroyFunc destroyFunc,
+ std::array<typename T::Handle, count> handles,
+ IndexSequence<Is...>) noexcept
+{
+ return {T{handles[Is], {parent, destroyFunc}}...};
+}
+
+template<class T, class Parent, class DestroyFunc, size_t count>
+std::array<T, count>
+make_handle_array(Parent parent,
+ DestroyFunc destroyFunc,
+ std::array<typename T::Handle, count> handles) noexcept
+{
+ return make_handle_array_h<T, Parent, DestroyFunc, count>(
+ parent, destroyFunc, handles, makeIndexSequence<count>());
+}
+
+namespace detail {
+
+template<class Value, class Vector, class Func, class... Args>
+inline VkResult
+wrapVectorAccessor(Vector& vector, Func func, Args... args) noexcept
+{
+ uint32_t count = 0u;
+ VkResult r = func(args..., &count, nullptr);
+ if (r > VK_INCOMPLETE) {
+ vector.clear();
+ return r;
+ }
+
+ vector = Vector(count);
+ if ((r = func(args..., &count, vector.data()))) {
+ vector.clear();
+ return r;
+ }
+
+ return VK_SUCCESS;
+}
+
+} // namespace detail
+
+class VulkanApi;
+
+struct MappedMemory {
+ MappedMemory() noexcept = default;
+
+ MappedMemory(const VulkanApi& api,
+ VkDevice device,
+ VkDeviceMemory memory,
+ void* data) noexcept
+ : _api{&api}
+ , _device{device}
+ , _memory{memory}
+ , _data{data}
+ {}
+
+ MappedMemory(const MappedMemory&) = delete;
+ MappedMemory& operator=(const MappedMemory&) = delete;
+
+ MappedMemory(MappedMemory&& mappedMemory) noexcept
+ : _api{mappedMemory._api}
+ , _device{mappedMemory._device}
+ , _memory{mappedMemory._memory}
+ , _data{mappedMemory._data}
+ {
+ mappedMemory._device = {};
+ mappedMemory._memory = {};
+ mappedMemory._data = {};
+ }
+
+ MappedMemory& operator=(MappedMemory&& mappedMemory) noexcept
+ {
+ std::swap(_api, mappedMemory._api);
+ std::swap(_device, mappedMemory._device);
+ std::swap(_memory, mappedMemory._memory);
+ std::swap(_data, mappedMemory._data);
+ return *this;
+ }
+
+ ~MappedMemory() noexcept;
+
+ const void* get() const noexcept { return _data; }
+ void* get() noexcept { return _data; }
+
+private:
+ const VulkanApi* _api{};
+ VkDevice _device{};
+ VkDeviceMemory _memory{};
+ void* _data{};
+};
+
+class VulkanInitApi
+{
+public:
+ template<typename NotFoundFunc>
+ VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr,
+ NotFoundFunc notFound) noexcept
+ {
+#define SK_INIT(name) \
+ do { \
+ if (!(name = PFN_##name(getInstanceProcAddr(NULL, #name)))) { \
+ notFound(#name); \
+ } \
+ } while (0)
+
+ vkGetInstanceProcAddr = pGetInstanceProcAddr;
+ SK_INIT(vkCreateInstance);
+ vkDestroyInstance = {}; // Loaded after we create an instance
+ SK_INIT(vkEnumerateInstanceExtensionProperties);
+ SK_INIT(vkEnumerateInstanceLayerProperties);
+
+ if (!vkCreateInstance || !vkEnumerateInstanceExtensionProperties ||
+ !vkEnumerateInstanceLayerProperties) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ return VK_SUCCESS;
+#undef SK_INIT
+ }
+
+ VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr) noexcept
+ {
+ return init(pGetInstanceProcAddr, [](const char*) {});
+ }
+
+ PFN_vkVoidFunction getInstanceProcAddr(VkInstance instance,
+ const char* const name) const noexcept
+ {
+ return vkGetInstanceProcAddr(instance, name);
+ }
+
+ VkResult createInstance(const VkInstanceCreateInfo& createInfo,
+ Instance& instance) noexcept
+ {
+ VkInstance h = {};
+ if (const VkResult r = vkCreateInstance(&createInfo, nullptr, &h)) {
+ return r;
+ }
+
+ if (!h) {
+ // Shouldn't actually happen, but this lets the compiler know that
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ if (!vkDestroyInstance) {
+ vkDestroyInstance = PFN_vkDestroyInstance(
+ getInstanceProcAddr(instance, "vkDestroyInstance"));
+ }
+
+ instance = {h, {vkDestroyInstance}};
+ return VK_SUCCESS;
+ }
+
+ template<class Vector>
+ VkResult enumerateInstanceExtensionProperties(
+ Vector& properties) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkExtensionProperties>(
+ properties, vkEnumerateInstanceExtensionProperties, nullptr);
+ }
+
+ template<class Vector>
+ VkResult enumerateInstanceExtensionProperties(
+ const char* const layerName,
+ Vector& properties) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkExtensionProperties>(
+ properties, vkEnumerateInstanceExtensionProperties, layerName);
+ }
+
+ template<class Vector>
+ VkResult enumerateInstanceLayerProperties(Vector& properties) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkLayerProperties>(
+ properties, vkEnumerateInstanceLayerProperties);
+ }
+
+private:
+ PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{};
+
+#define SK_FUNC(name) \
+ PFN_##name name {}
+
+ SK_FUNC(vkCreateInstance);
+ SK_FUNC(vkDestroyInstance);
+ SK_FUNC(vkEnumerateInstanceExtensionProperties);
+ SK_FUNC(vkEnumerateInstanceLayerProperties);
+
+#undef SK_FUNC
+};
+
+class VulkanApi
+{
+public:
+ template<typename NotFoundFunc>
+ VkResult init(const VulkanInitApi& initApi,
+ const Instance& instance,
+ NotFoundFunc notFound) noexcept
+ {
+ VkResult r = VK_SUCCESS;
+
+ const auto notFoundWrapper = [&r, notFound](const char* name) {
+ r = VK_INCOMPLETE;
+ notFound(name);
+ };
+
+#define SK_INIT(name) \
+ do { \
+ if (!(name = PFN_##name(initApi.getInstanceProcAddr(instance, #name)))) { \
+ notFoundWrapper(#name); \
+ } \
+ } while (0)
+
+ SK_INIT(vkAllocateCommandBuffers);
+ SK_INIT(vkAllocateDescriptorSets);
+ SK_INIT(vkAllocateMemory);
+ SK_INIT(vkBeginCommandBuffer);
+ SK_INIT(vkBindBufferMemory);
+ SK_INIT(vkBindImageMemory);
+ SK_INIT(vkCmdBeginQuery);
+ SK_INIT(vkCmdBeginRenderPass);
+ SK_INIT(vkCmdBindDescriptorSets);
+ SK_INIT(vkCmdBindIndexBuffer);
+ SK_INIT(vkCmdBindPipeline);
+ SK_INIT(vkCmdBindVertexBuffers);
+ SK_INIT(vkCmdBlitImage);
+ SK_INIT(vkCmdClearAttachments);
+ SK_INIT(vkCmdClearColorImage);
+ SK_INIT(vkCmdClearDepthStencilImage);
+ SK_INIT(vkCmdCopyBuffer);
+ SK_INIT(vkCmdCopyBufferToImage);
+ SK_INIT(vkCmdCopyImage);
+ SK_INIT(vkCmdCopyImageToBuffer);
+ SK_INIT(vkCmdCopyQueryPoolResults);
+ SK_INIT(vkCmdDispatch);
+ SK_INIT(vkCmdDispatchIndirect);
+ SK_INIT(vkCmdDraw);
+ SK_INIT(vkCmdDrawIndexed);
+ SK_INIT(vkCmdDrawIndexedIndirect);
+ SK_INIT(vkCmdDrawIndirect);
+ SK_INIT(vkCmdEndQuery);
+ SK_INIT(vkCmdEndRenderPass);
+ SK_INIT(vkCmdExecuteCommands);
+ SK_INIT(vkCmdFillBuffer);
+ SK_INIT(vkCmdNextSubpass);
+ SK_INIT(vkCmdPipelineBarrier);
+ SK_INIT(vkCmdPushConstants);
+ SK_INIT(vkCmdResetEvent);
+ SK_INIT(vkCmdResetQueryPool);
+ SK_INIT(vkCmdResolveImage);
+ SK_INIT(vkCmdSetBlendConstants);
+ SK_INIT(vkCmdSetDepthBias);
+ SK_INIT(vkCmdSetDepthBounds);
+ SK_INIT(vkCmdSetEvent);
+ SK_INIT(vkCmdSetLineWidth);
+ SK_INIT(vkCmdSetScissor);
+ SK_INIT(vkCmdSetStencilCompareMask);
+ SK_INIT(vkCmdSetStencilReference);
+ SK_INIT(vkCmdSetStencilWriteMask);
+ SK_INIT(vkCmdSetViewport);
+ SK_INIT(vkCmdUpdateBuffer);
+ SK_INIT(vkCmdWaitEvents);
+ SK_INIT(vkCmdWriteTimestamp);
+ SK_INIT(vkCreateBuffer);
+ SK_INIT(vkCreateBufferView);
+ SK_INIT(vkCreateCommandPool);
+ SK_INIT(vkCreateComputePipelines);
+ SK_INIT(vkCreateDescriptorPool);
+ SK_INIT(vkCreateDescriptorSetLayout);
+ SK_INIT(vkCreateDevice);
+ SK_INIT(vkCreateEvent);
+ SK_INIT(vkCreateFence);
+ SK_INIT(vkCreateFramebuffer);
+ SK_INIT(vkCreateGraphicsPipelines);
+ SK_INIT(vkCreateImage);
+ SK_INIT(vkCreateImageView);
+ SK_INIT(vkCreateInstance);
+ SK_INIT(vkCreatePipelineCache);
+ SK_INIT(vkCreatePipelineLayout);
+ SK_INIT(vkCreateQueryPool);
+ SK_INIT(vkCreateRenderPass);
+ SK_INIT(vkCreateSampler);
+ SK_INIT(vkCreateSemaphore);
+ SK_INIT(vkCreateShaderModule);
+ SK_INIT(vkDestroyBuffer);
+ SK_INIT(vkDestroyBufferView);
+ SK_INIT(vkDestroyCommandPool);
+ SK_INIT(vkDestroyDescriptorPool);
+ SK_INIT(vkDestroyDescriptorSetLayout);
+ SK_INIT(vkDestroyDevice);
+ SK_INIT(vkDestroyEvent);
+ SK_INIT(vkDestroyFence);
+ SK_INIT(vkDestroyFramebuffer);
+ SK_INIT(vkDestroyImage);
+ SK_INIT(vkDestroyImageView);
+ SK_INIT(vkDestroyPipeline);
+ SK_INIT(vkDestroyPipelineCache);
+ SK_INIT(vkDestroyPipelineLayout);
+ SK_INIT(vkDestroyQueryPool);
+ SK_INIT(vkDestroyRenderPass);
+ SK_INIT(vkDestroySampler);
+ SK_INIT(vkDestroySemaphore);
+ SK_INIT(vkDestroyShaderModule);
+ SK_INIT(vkDeviceWaitIdle);
+ SK_INIT(vkEndCommandBuffer);
+ SK_INIT(vkEnumerateDeviceExtensionProperties);
+ SK_INIT(vkEnumerateDeviceLayerProperties);
+ SK_INIT(vkEnumeratePhysicalDevices);
+ SK_INIT(vkFlushMappedMemoryRanges);
+ SK_INIT(vkFreeCommandBuffers);
+ SK_INIT(vkFreeDescriptorSets);
+ SK_INIT(vkFreeMemory);
+ SK_INIT(vkGetBufferMemoryRequirements);
+ SK_INIT(vkGetDeviceMemoryCommitment);
+ SK_INIT(vkGetDeviceProcAddr);
+ SK_INIT(vkGetDeviceQueue);
+ SK_INIT(vkGetEventStatus);
+ SK_INIT(vkGetFenceStatus);
+ SK_INIT(vkGetImageMemoryRequirements);
+ SK_INIT(vkGetImageSparseMemoryRequirements);
+ SK_INIT(vkGetImageSubresourceLayout);
+ SK_INIT(vkGetInstanceProcAddr);
+ SK_INIT(vkGetPhysicalDeviceFeatures);
+ SK_INIT(vkGetPhysicalDeviceFormatProperties);
+ SK_INIT(vkGetPhysicalDeviceImageFormatProperties);
+ SK_INIT(vkGetPhysicalDeviceMemoryProperties);
+ SK_INIT(vkGetPhysicalDeviceProperties);
+ SK_INIT(vkGetPhysicalDeviceQueueFamilyProperties);
+ SK_INIT(vkGetPhysicalDeviceSparseImageFormatProperties);
+ SK_INIT(vkGetPipelineCacheData);
+ SK_INIT(vkGetQueryPoolResults);
+ SK_INIT(vkGetRenderAreaGranularity);
+ SK_INIT(vkInvalidateMappedMemoryRanges);
+ SK_INIT(vkMapMemory);
+ SK_INIT(vkMergePipelineCaches);
+ SK_INIT(vkQueueBindSparse);
+ SK_INIT(vkQueueSubmit);
+ SK_INIT(vkQueueWaitIdle);
+ SK_INIT(vkResetCommandBuffer);
+ SK_INIT(vkResetCommandPool);
+ SK_INIT(vkResetDescriptorPool);
+ SK_INIT(vkResetEvent);
+ SK_INIT(vkResetFences);
+ SK_INIT(vkSetEvent);
+ SK_INIT(vkUnmapMemory);
+ SK_INIT(vkUpdateDescriptorSets);
+ SK_INIT(vkWaitForFences);
+
+ // VK_EXT_debug_report
+ SK_INIT(vkCreateDebugReportCallbackEXT);
+ SK_INIT(vkDebugReportMessageEXT);
+ SK_INIT(vkDestroyDebugReportCallbackEXT);
+
+ // VK_KHR_surface
+ SK_INIT(vkDestroySurfaceKHR);
+ SK_INIT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+ SK_INIT(vkGetPhysicalDeviceSurfaceFormatsKHR);
+ SK_INIT(vkGetPhysicalDeviceSurfacePresentModesKHR);
+ SK_INIT(vkGetPhysicalDeviceSurfaceSupportKHR);
+
+ // VK_KHR_swapchain
+ SK_INIT(vkAcquireNextImageKHR);
+ SK_INIT(vkCreateSwapchainKHR);
+ SK_INIT(vkDestroySwapchainKHR);
+ SK_INIT(vkGetDeviceGroupPresentCapabilitiesKHR);
+ SK_INIT(vkGetDeviceGroupSurfacePresentModesKHR);
+ SK_INIT(vkGetPhysicalDevicePresentRectanglesKHR);
+ SK_INIT(vkGetSwapchainImagesKHR);
+ SK_INIT(vkQueuePresentKHR);
+
+#undef SK_INIT
+
+ return r;
+ }
+
+ VkResult init(const VulkanInitApi& initApi, const Instance& instance) noexcept
+ {
+ return init(initApi, instance, [](const char*) {});
+ }
+
+ template<class VkCommandBufferVector>
+ VkResult allocateCommandBuffers(
+ const Device& device,
+ const VkCommandBufferAllocateInfo& allocateInfo,
+ CommandBuffers<VkCommandBufferVector>& commandBuffers) const noexcept
+ {
+ VkCommandBufferVector rawCommandBuffers =
+ VkCommandBufferVector(allocateInfo.commandBufferCount);
+
+ if (const VkResult r = vkAllocateCommandBuffers(
+ device, &allocateInfo, rawCommandBuffers.data())) {
+ return r;
+ }
+
+ commandBuffers = CommandBuffers<VkCommandBufferVector>{
+ allocateInfo.commandBufferCount,
+ std::move(rawCommandBuffers),
+ PoolDeleter<VkCommandBuffer, VkCommandPool, void>{
+ device,
+ allocateInfo.commandPool,
+ allocateInfo.commandBufferCount,
+ vkFreeCommandBuffers}};
+ return VK_SUCCESS;
+ }
+
+ template<class VkDescriptorSetVector>
+ VkResult allocateDescriptorSets(
+ const Device& device,
+ const VkDescriptorSetAllocateInfo& allocateInfo,
+ DescriptorSets<VkDescriptorSetVector>& descriptorSets) const noexcept
+ {
+ auto descriptorSetVector =
+ VkDescriptorSetVector(allocateInfo.descriptorSetCount);
+
+ if (const VkResult r = vkAllocateDescriptorSets(
+ device, &allocateInfo, descriptorSetVector.data())) {
+ return r;
+ }
+
+ descriptorSets = DescriptorSets<VkDescriptorSetVector>{
+ allocateInfo.descriptorSetCount,
+ std::move(descriptorSetVector),
+ PoolDeleter<VkDescriptorSet, VkDescriptorPool, VkResult>{
+ device,
+ allocateInfo.descriptorPool,
+ allocateInfo.descriptorSetCount,
+ vkFreeDescriptorSets}};
+ return VK_SUCCESS;
+ }
+
+ VkResult bindBufferMemory(const Device& device,
+ const Buffer& buffer,
+ const DeviceMemory& memory,
+ VkDeviceSize memoryOffset) const noexcept
+ {
+ return vkBindBufferMemory
+ ? vkBindBufferMemory(device, buffer, memory, memoryOffset)
+ : VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+
+ VkResult createBuffer(const Device& device,
+ const VkBufferCreateInfo& createInfo,
+ Buffer& buffer) const noexcept
+ {
+ VkBuffer h = {};
+ const VkResult r = vkCreateBuffer(device, &createInfo, nullptr, &h);
+ return wrapResult(r, h, {device, vkDestroyBuffer}, buffer);
+ }
+
+ VkResult createBufferView(const Device& device,
+ const VkBufferViewCreateInfo& createInfo,
+ BufferView& bufferView) const noexcept
+ {
+ VkBufferView h = {};
+ const VkResult r = vkCreateBufferView(device, &createInfo, nullptr, &h);
+ return wrapResult(r, h, {device, vkDestroyBufferView}, bufferView);
+ }
+
+ VkResult createCommandPool(const Device& device,
+ const VkCommandPoolCreateInfo& createInfo,
+ CommandPool& commandPool) const noexcept
+ {
+ VkCommandPool h = {};
+ const VkResult r = vkCreateCommandPool(device, &createInfo, nullptr, &h);
+ return wrapResult(r, h, {device, vkDestroyCommandPool}, commandPool);
+ }
+
+ VkResult createDescriptorPool(const Device& device,
+ const VkDescriptorPoolCreateInfo& createInfo,
+ DescriptorPool& descriptorPool) const noexcept
+ {
+ VkDescriptorPool h = {};
+ const VkResult r = vkCreateDescriptorPool(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyDescriptorPool}, descriptorPool);
+ }
+
+ VkResult createDescriptorSetLayout(
+ const Device& device,
+ const VkDescriptorSetLayoutCreateInfo& createInfo,
+ DescriptorSetLayout& descriptorSetLayout) const noexcept
+ {
+ VkDescriptorSetLayout h = {};
+ const VkResult r =
+ vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &h);
+
+ return wrapResult(
+ r, h, {device, vkDestroyDescriptorSetLayout}, descriptorSetLayout);
+ }
+
+ VkResult createDevice(const PhysicalDevice& physicalDevice,
+ const VkDeviceCreateInfo& createInfo,
+ Device& result) const noexcept
+ {
+ VkDevice h = {};
+ const VkResult r = vkCreateDevice(physicalDevice, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {vkDestroyDevice}, result);
+ }
+
+ VkResult createEvent(const Device& device,
+ const VkEventCreateInfo& createInfo,
+ Event& event) const noexcept
+ {
+ VkEvent h = {};
+ const VkResult r = vkCreateEvent(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyEvent}, event);
+ }
+
+ VkResult createFence(const Device& device,
+ const VkFenceCreateInfo& createInfo,
+ Fence& fence) const noexcept
+ {
+ VkFence h = {};
+ const VkResult r = vkCreateFence(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyFence}, fence);
+ }
+
+ VkResult createFramebuffer(const Device& device,
+ const VkFramebufferCreateInfo& createInfo,
+ Framebuffer& framebuffer) const noexcept
+ {
+ VkFramebuffer h = {};
+ const VkResult r = vkCreateFramebuffer(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyFramebuffer}, framebuffer);
+ }
+
+ VkResult createImage(const Device& device,
+ const VkImageCreateInfo& createInfo,
+ Image& image) const noexcept
+ {
+ VkImage h = {};
+ const VkResult r = vkCreateImage(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyImage}, image);
+ }
+
+ VkResult createImageView(const Device& device,
+ const VkImageViewCreateInfo& createInfo,
+ ImageView& imageView) const noexcept
+ {
+ VkImageView h = {};
+ const VkResult r = vkCreateImageView(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyImageView}, imageView);
+ }
+
+ template<size_t count>
+ VkResult createGraphicsPipelines(
+ const Device& device,
+ const OptionalParameter<PipelineCache>& pipelineCache,
+ const std::array<VkGraphicsPipelineCreateInfo, count>& createInfos,
+ std::array<Pipeline, count>& pipelines) const noexcept
+ {
+ std::array<VkPipeline, count> pipelineHandles{};
+
+ if (const VkResult r =
+ vkCreateGraphicsPipelines(device,
+ pipelineCache.get(),
+ static_cast<uint32_t>(createInfos.size()),
+ createInfos.data(),
+ nullptr,
+ pipelineHandles.data())) {
+ return r;
+ }
+
+ pipelines = make_handle_array<Pipeline>(
+ device.get(), vkDestroyPipeline, pipelineHandles);
+ return VK_SUCCESS;
+ }
+
+ VkResult createPipelineCache(const Device& device,
+ const VkPipelineCacheCreateInfo& createInfo,
+ PipelineCache& pipelineCache) const noexcept
+ {
+ VkPipelineCache h = {};
+ const VkResult r = vkCreatePipelineCache(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyPipelineCache}, pipelineCache);
+ }
+
+ VkResult createPipelineLayout(const Device& device,
+ const VkPipelineLayoutCreateInfo& createInfo,
+ PipelineLayout& pipelineLayout) const noexcept
+ {
+ VkPipelineLayout h = {};
+ const VkResult r = vkCreatePipelineLayout(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyPipelineLayout}, pipelineLayout);
+ }
+
+ VkResult createQueryPool(const Device& device,
+ const VkQueryPoolCreateInfo& createInfo,
+ QueryPool& queryPool) const noexcept
+ {
+ VkQueryPool h = {};
+ const VkResult r = vkCreateQueryPool(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyQueryPool}, queryPool);
+ }
+
+ VkResult createRenderPass(const Device& device,
+ const VkRenderPassCreateInfo& createInfo,
+ RenderPass& renderPass) const noexcept
+ {
+ VkRenderPass h = {};
+ const VkResult r = vkCreateRenderPass(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyRenderPass}, renderPass);
+ }
+
+ VkResult createSampler(const Device& device,
+ const VkSamplerCreateInfo& createInfo,
+ Sampler& sampler) const noexcept
+ {
+ VkSampler h = {};
+ const VkResult r = vkCreateSampler(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroySampler}, sampler);
+ }
+
+ VkResult createSemaphore(const Device& device,
+ const VkSemaphoreCreateInfo& createInfo,
+ Semaphore& semaphore) const noexcept
+ {
+ VkSemaphore h = {};
+ const VkResult r = vkCreateSemaphore(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroySemaphore}, semaphore);
+ }
+
+ VkResult createShaderModule(const Device& device,
+ const VkShaderModuleCreateInfo& createInfo,
+ ShaderModule& shaderModule) const noexcept
+ {
+ VkShaderModule h = {};
+ const VkResult r = vkCreateShaderModule(device, &createInfo, nullptr, &h);
+
+ return wrapResult(r, h, {device, vkDestroyShaderModule}, shaderModule);
+ }
+
+ VkResult deviceWaitIdle(const Device& device) const noexcept
+ {
+ return vkDeviceWaitIdle(device);
+ }
+
+ template<class Vector>
+ VkResult enumerateDeviceExtensionProperties(
+ const PhysicalDevice& physicalDevice,
+ const char* const layerName,
+ Vector& properties) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkExtensionProperties>(
+ properties,
+ vkEnumerateDeviceExtensionProperties,
+ physicalDevice,
+ layerName);
+ }
+
+ template<class Vector>
+ VkResult enumerateDeviceExtensionProperties(
+ const PhysicalDevice& physicalDevice,
+ Vector& properties) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkExtensionProperties>(
+ properties,
+ vkEnumerateDeviceExtensionProperties,
+ physicalDevice,
+ nullptr);
+ }
+
+ template<class Vector>
+ VkResult enumeratePhysicalDevices(const Instance& instance,
+ Vector& physicalDevices) const noexcept
+ {
+ uint32_t count = 0u;
+ VkResult r = vkEnumeratePhysicalDevices(instance, &count, nullptr);
+ if (r > VK_INCOMPLETE) {
+ return r;
+ }
+
+ physicalDevices = Vector(count);
+ if ((r = vkEnumeratePhysicalDevices(
+ instance, &count, physicalDevices.data()))) {
+ return r;
+ }
+
+ return VK_SUCCESS;
+ }
+
+ sk::Queue getDeviceQueue(const Device& device,
+ const uint32_t queueFamilyIndex,
+ const uint32_t queueIndex) const noexcept
+ {
+ VkQueue queue{};
+ vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, &queue);
+ return sk::Queue{queue};
+ }
+
+ VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties(
+ VkPhysicalDevice physicalDevice) const noexcept
+ {
+ VkPhysicalDeviceMemoryProperties properties{};
+ vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties);
+ return properties;
+ }
+
+ VkPhysicalDeviceProperties getPhysicalDeviceProperties(
+ const PhysicalDevice& physicalDevice) const noexcept
+ {
+ VkPhysicalDeviceProperties properties{};
+ vkGetPhysicalDeviceProperties(physicalDevice, &properties);
+ return properties;
+ }
+
+ template<class Vector>
+ VkResult getPhysicalDeviceQueueFamilyProperties(
+ const PhysicalDevice& physicalDevice,
+ Vector& queueFamilyProperties) const noexcept
+ {
+ uint32_t count = 0u;
+ vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr);
+
+ queueFamilyProperties = Vector(count);
+ vkGetPhysicalDeviceQueueFamilyProperties(
+ physicalDevice, &count, queueFamilyProperties.data());
+
+ return VK_SUCCESS;
+ }
+
+ VkMemoryRequirements getBufferMemoryRequirements(
+ const Device& device,
+ const Buffer& buffer) const noexcept
+ {
+ VkMemoryRequirements requirements;
+ vkGetBufferMemoryRequirements(device, buffer, &requirements);
+ return requirements;
+ }
+
+ VkResult allocateMemory(const Device& device,
+ const VkMemoryAllocateInfo& info,
+ DeviceMemory& memory) const noexcept
+ {
+ VkDeviceMemory h = {};
+ if (const VkResult r = vkAllocateMemory(device, &info, nullptr, &h)) {
+ return r;
+ }
+
+ if (!h) {
+ return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+ }
+
+ memory = DeviceMemory{h, {device, vkFreeMemory}};
+ return VK_SUCCESS;
+ }
+
+ VkResult mapMemory(const Device& device,
+ const DeviceMemory& memory,
+ VkDeviceSize offset,
+ VkDeviceSize size,
+ VkMemoryMapFlags flags,
+ MappedMemory& mappedMemory) const noexcept
+ {
+ void* data = nullptr;
+ if (const VkResult r =
+ vkMapMemory(device, memory, offset, size, flags, &data)) {
+ return r;
+ }
+
+ mappedMemory = MappedMemory{*this, device, memory, data};
+ return VK_SUCCESS;
+ }
+
+ VkResult queueSubmit(const Queue& queue,
+ uint32_t submitCount,
+ const VkSubmitInfo& submits,
+ const Fence& fence) const noexcept
+ {
+ return vkQueueSubmit(queue, submitCount, &submits, fence);
+ }
+
+ VkResult queueSubmit(const Queue& queue,
+ const VkSubmitInfo& submit,
+ const Fence& fence) const noexcept
+ {
+ return vkQueueSubmit(queue, 1u, &submit, fence);
+ }
+
+ template<size_t descriptorWriteCount, size_t descriptorCopyCount>
+ void updateDescriptorSets(
+ const Device& device,
+ std::array<VkWriteDescriptorSet, descriptorWriteCount> descriptorWrites,
+ std::array<VkCopyDescriptorSet, descriptorCopyCount> descriptorCopies)
+ const noexcept
+ {
+ vkUpdateDescriptorSets(device,
+ static_cast<uint32_t>(descriptorWrites.size()),
+ descriptorWrites.data(),
+ static_cast<uint32_t>(descriptorCopies.size()),
+ descriptorCopies.data());
+ }
+
+ VkResult resetFence(const Device& device, const Fence& fence) const noexcept
+ {
+ VkFence h = fence;
+ return vkResetFences(device, 1u, &h);
+ }
+
+ VkResult waitForFence(const Device& device,
+ const Fence& fence,
+ uint64_t timeout) const noexcept
+ {
+ VkFence h = fence;
+ return vkWaitForFences(device, 1u, &h, VK_TRUE, timeout);
+ }
+
+ VkResult waitForFence(const Device& device, const Fence& fence) const noexcept
+ {
+ VkFence h = fence;
+ return vkWaitForFences(device, 1u, &h, VK_TRUE, UINT64_MAX);
+ }
+
+ // Scoped command buffer interface
+ SYBOK_NODISCARD
+ CommandScope beginCommandBuffer(
+ VkCommandBuffer commandBuffer,
+ VkCommandBufferBeginInfo beginInfo) const noexcept;
+
+ // VK_EXT_debug_report
+
+ VkResult createDebugReportCallbackEXT(
+ const Instance& instance,
+ const VkDebugReportCallbackCreateInfoEXT& createInfo,
+ DebugReportCallbackEXT& callback) const noexcept
+ {
+ VkDebugReportCallbackEXT h = {};
+
+ if (const VkResult r =
+ vkCreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &h)) {
+ return r;
+ }
+
+ if (!h) {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+
+ callback = {h, {instance, vkDestroyDebugReportCallbackEXT}};
+ return VK_SUCCESS;
+ }
+
+ // VK_KHR_surface
+
+ VkResult getPhysicalDeviceSurfaceCapabilitiesKHR(
+ const PhysicalDevice& physicalDevice,
+ const SurfaceKHR& surface,
+ VkSurfaceCapabilitiesKHR& capabilities) const noexcept
+ {
+ return vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ physicalDevice, surface, &capabilities);
+ }
+
+ template<typename Vector>
+ VkResult getPhysicalDeviceSurfaceFormatsKHR(
+ const PhysicalDevice& physicalDevice,
+ const SurfaceKHR& surface,
+ Vector& surfaceFormats) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkSurfaceFormatKHR>(
+ surfaceFormats,
+ vkGetPhysicalDeviceSurfaceFormatsKHR,
+ physicalDevice,
+ surface.get());
+ }
+
+ template<typename Vector>
+ VkResult getPhysicalDeviceSurfacePresentModesKHR(
+ const PhysicalDevice& physicalDevice,
+ const SurfaceKHR& surface,
+ Vector& presentModes) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkPresentModeKHR>(
+ presentModes,
+ vkGetPhysicalDeviceSurfacePresentModesKHR,
+ physicalDevice,
+ surface.get());
+ }
+
+ VkResult getPhysicalDeviceSurfaceSupportKHR(
+ const PhysicalDevice& physicalDevice,
+ uint32_t queueFamilyIndex,
+ const SurfaceKHR& surface,
+ bool& supported) const noexcept
+ {
+ VkBool32 s = {};
+
+ if (VkResult r = vkGetPhysicalDeviceSurfaceSupportKHR(
+ physicalDevice, queueFamilyIndex, surface, &s)) {
+ return r;
+ }
+
+ supported = s;
+ return VK_SUCCESS;
+ }
+
+ // VK_KHR_swapchain
+
+ VkResult acquireNextImageKHR(const Device& device,
+ const SwapchainKHR& swapchain,
+ uint64_t timeout,
+ const Semaphore& semaphore,
+ const OptionalParameter<Fence>& fence,
+ uint32_t* pImageIndex) const noexcept
+ {
+ return vkAcquireNextImageKHR(
+ device, swapchain, timeout, semaphore, fence.get(), pImageIndex);
+ }
+
+ template<class Vector>
+ VkResult getSwapchainImagesKHR(const Device& device,
+ const SwapchainKHR& swapchain,
+ Vector& images) const noexcept
+ {
+ return detail::wrapVectorAccessor<VkImage>(
+ images, vkGetSwapchainImagesKHR, device.get(), swapchain.get());
+ }
+
+ VkResult createSwapchainKHR(const Device& device,
+ const VkSwapchainCreateInfoKHR& createInfo,
+ SwapchainKHR& swapchain) const noexcept
+ {
+ VkSwapchainKHR h = {};
+ const VkResult r = vkCreateSwapchainKHR(device, &createInfo, nullptr, &h);
+
+ if (r) {
+ return r;
+ }
+
+ if (!h) {
+ return VK_ERROR_INCOMPATIBLE_DRIVER;
+ }
+
+ swapchain = {h, {device, vkDestroySwapchainKHR}};
+ return VK_SUCCESS;
+ }
+
+ VkResult queuePresentKHR(const Queue& queue,
+ const VkPresentInfoKHR& presentInfo) const noexcept
+ {
+ return vkQueuePresentKHR(queue, &presentInfo);
+ }
+
+#define SK_FUNC(name) \
+ PFN_##name name {} // NOLINT
+
+ // Vulkan 1.0 Core
+ SK_FUNC(vkAllocateCommandBuffers);
+ SK_FUNC(vkAllocateDescriptorSets);
+ SK_FUNC(vkAllocateMemory);
+ SK_FUNC(vkBeginCommandBuffer);
+ SK_FUNC(vkBindBufferMemory);
+ SK_FUNC(vkBindImageMemory);
+ SK_FUNC(vkCmdBeginQuery);
+ SK_FUNC(vkCmdBeginRenderPass);
+ SK_FUNC(vkCmdBindDescriptorSets);
+ SK_FUNC(vkCmdBindIndexBuffer);
+ SK_FUNC(vkCmdBindPipeline);
+ SK_FUNC(vkCmdBindVertexBuffers);
+ SK_FUNC(vkCmdBlitImage);
+ SK_FUNC(vkCmdClearAttachments);
+ SK_FUNC(vkCmdClearColorImage);
+ SK_FUNC(vkCmdClearDepthStencilImage);
+ SK_FUNC(vkCmdCopyBuffer);
+ SK_FUNC(vkCmdCopyBufferToImage);
+ SK_FUNC(vkCmdCopyImage);
+ SK_FUNC(vkCmdCopyImageToBuffer);
+ SK_FUNC(vkCmdCopyQueryPoolResults);
+ SK_FUNC(vkCmdDispatch);
+ SK_FUNC(vkCmdDispatchIndirect);
+ SK_FUNC(vkCmdDraw);
+ SK_FUNC(vkCmdDrawIndexed);
+ SK_FUNC(vkCmdDrawIndexedIndirect);
+ SK_FUNC(vkCmdDrawIndirect);
+ SK_FUNC(vkCmdEndQuery);
+ SK_FUNC(vkCmdEndRenderPass);
+ SK_FUNC(vkCmdExecuteCommands);
+ SK_FUNC(vkCmdFillBuffer);
+ SK_FUNC(vkCmdNextSubpass);
+ SK_FUNC(vkCmdPipelineBarrier);
+ SK_FUNC(vkCmdPushConstants);
+ SK_FUNC(vkCmdResetEvent);
+ SK_FUNC(vkCmdResetQueryPool);
+ SK_FUNC(vkCmdResolveImage);
+ SK_FUNC(vkCmdSetBlendConstants);
+ SK_FUNC(vkCmdSetDepthBias);
+ SK_FUNC(vkCmdSetDepthBounds);
+ SK_FUNC(vkCmdSetEvent);
+ SK_FUNC(vkCmdSetLineWidth);
+ SK_FUNC(vkCmdSetScissor);
+ SK_FUNC(vkCmdSetStencilCompareMask);
+ SK_FUNC(vkCmdSetStencilReference);
+ SK_FUNC(vkCmdSetStencilWriteMask);
+ SK_FUNC(vkCmdSetViewport);
+ SK_FUNC(vkCmdUpdateBuffer);
+ SK_FUNC(vkCmdWaitEvents);
+ SK_FUNC(vkCmdWriteTimestamp);
+ SK_FUNC(vkCreateBuffer);
+ SK_FUNC(vkCreateBufferView);
+ SK_FUNC(vkCreateCommandPool);
+ SK_FUNC(vkCreateComputePipelines);
+ SK_FUNC(vkCreateDescriptorPool);
+ SK_FUNC(vkCreateDescriptorSetLayout);
+ SK_FUNC(vkCreateDevice);
+ SK_FUNC(vkCreateEvent);
+ SK_FUNC(vkCreateFence);
+ SK_FUNC(vkCreateFramebuffer);
+ SK_FUNC(vkCreateGraphicsPipelines);
+ SK_FUNC(vkCreateImage);
+ SK_FUNC(vkCreateImageView);
+ SK_FUNC(vkCreateInstance);
+ SK_FUNC(vkCreatePipelineCache);
+ SK_FUNC(vkCreatePipelineLayout);
+ SK_FUNC(vkCreateQueryPool);
+ SK_FUNC(vkCreateRenderPass);
+ SK_FUNC(vkCreateSampler);
+ SK_FUNC(vkCreateSemaphore);
+ SK_FUNC(vkCreateShaderModule);
+ SK_FUNC(vkDestroyBuffer);
+ SK_FUNC(vkDestroyBufferView);
+ SK_FUNC(vkDestroyCommandPool);
+ SK_FUNC(vkDestroyDescriptorPool);
+ SK_FUNC(vkDestroyDescriptorSetLayout);
+ SK_FUNC(vkDestroyDevice);
+ SK_FUNC(vkDestroyEvent);
+ SK_FUNC(vkDestroyFence);
+ SK_FUNC(vkDestroyFramebuffer);
+ SK_FUNC(vkDestroyImage);
+ SK_FUNC(vkDestroyImageView);
+ SK_FUNC(vkDestroyPipeline);
+ SK_FUNC(vkDestroyPipelineCache);
+ SK_FUNC(vkDestroyPipelineLayout);
+ SK_FUNC(vkDestroyQueryPool);
+ SK_FUNC(vkDestroyRenderPass);
+ SK_FUNC(vkDestroySampler);
+ SK_FUNC(vkDestroySemaphore);
+ SK_FUNC(vkDestroyShaderModule);
+ SK_FUNC(vkDeviceWaitIdle);
+ SK_FUNC(vkEndCommandBuffer);
+ SK_FUNC(vkEnumerateDeviceExtensionProperties);
+ SK_FUNC(vkEnumerateDeviceLayerProperties);
+ SK_FUNC(vkEnumeratePhysicalDevices);
+ SK_FUNC(vkFlushMappedMemoryRanges);
+ SK_FUNC(vkFreeCommandBuffers);
+ SK_FUNC(vkFreeDescriptorSets);
+ SK_FUNC(vkFreeMemory);
+ SK_FUNC(vkGetBufferMemoryRequirements);
+ SK_FUNC(vkGetDeviceMemoryCommitment);
+ SK_FUNC(vkGetDeviceProcAddr);
+ SK_FUNC(vkGetDeviceQueue);
+ SK_FUNC(vkGetEventStatus);
+ SK_FUNC(vkGetFenceStatus);
+ SK_FUNC(vkGetImageMemoryRequirements);
+ SK_FUNC(vkGetImageSparseMemoryRequirements);
+ SK_FUNC(vkGetImageSubresourceLayout);
+ SK_FUNC(vkGetInstanceProcAddr);
+ SK_FUNC(vkGetPhysicalDeviceFeatures);
+ SK_FUNC(vkGetPhysicalDeviceFormatProperties);
+ SK_FUNC(vkGetPhysicalDeviceImageFormatProperties);
+ SK_FUNC(vkGetPhysicalDeviceMemoryProperties);
+ SK_FUNC(vkGetPhysicalDeviceProperties);
+ SK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties);
+ SK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties);
+ SK_FUNC(vkGetPipelineCacheData);
+ SK_FUNC(vkGetQueryPoolResults);
+ SK_FUNC(vkGetRenderAreaGranularity);
+ SK_FUNC(vkInvalidateMappedMemoryRanges);
+ SK_FUNC(vkMapMemory);
+ SK_FUNC(vkMergePipelineCaches);
+ SK_FUNC(vkQueueBindSparse);
+ SK_FUNC(vkQueueSubmit);
+ SK_FUNC(vkQueueWaitIdle);
+ SK_FUNC(vkResetCommandBuffer);
+ SK_FUNC(vkResetCommandPool);
+ SK_FUNC(vkResetDescriptorPool);
+ SK_FUNC(vkResetEvent);
+ SK_FUNC(vkResetFences);
+ SK_FUNC(vkSetEvent);
+ SK_FUNC(vkUnmapMemory);
+ SK_FUNC(vkUpdateDescriptorSets);
+ SK_FUNC(vkWaitForFences);
+
+ // VK_EXT_debug_report
+ SK_FUNC(vkCreateDebugReportCallbackEXT);
+ SK_FUNC(vkDebugReportMessageEXT);
+ SK_FUNC(vkDestroyDebugReportCallbackEXT);
+
+ // VK_KHR_surface
+ SK_FUNC(vkDestroySurfaceKHR);
+ SK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+ SK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR);
+ SK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR);
+ SK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR);
+
+ // VK_KHR_swapchain
+ SK_FUNC(vkAcquireNextImageKHR);
+ SK_FUNC(vkCreateSwapchainKHR);
+ SK_FUNC(vkDestroySwapchainKHR);
+ SK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR);
+ SK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR);
+ SK_FUNC(vkGetPhysicalDevicePresentRectanglesKHR);
+ SK_FUNC(vkGetSwapchainImagesKHR);
+ SK_FUNC(vkQueuePresentKHR);
+
+#undef SK_FUNC
+
+private:
+ template<class T>
+ static inline VkResult wrapResult(const VkResult r,
+ const typename T::Handle handle,
+ typename T::Deleter&& deleter,
+ T& result) noexcept
+ {
+ if (r) {
+ return r;
+ }
+
+ if (!handle) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ result = T{handle, std::move(deleter)};
+ return VK_SUCCESS;
+ }
+};
+
+/// Scope for commands that work both inside and outside a render pass
+class CommonCommandScope
+{
+public:
+ CommonCommandScope(const VulkanApi& api,
+ VkCommandBuffer commandBuffer,
+ VkResult result) noexcept
+ : _api{api}
+ , _commandBuffer{commandBuffer}
+ , _result{result}
+ {}
+
+ CommonCommandScope(const CommonCommandScope&) noexcept = delete;
+ CommonCommandScope& operator=(const CommonCommandScope&) noexcept = delete;
+
+ CommonCommandScope(CommonCommandScope&& scope) noexcept
+ : _api{scope._api}
+ , _commandBuffer{scope._commandBuffer}
+ , _result{scope._result}
+ {
+ scope._commandBuffer = {};
+ }
+
+ CommonCommandScope& operator=(CommonCommandScope&&) = delete;
+
+ ~CommonCommandScope() noexcept = default;
+
+ explicit operator bool() const noexcept { return _result == VK_SUCCESS; }
+
+ VkResult error() const noexcept { return _result; }
+
+ void bindPipeline(VkPipelineBindPoint pipelineBindPoint,
+ VkPipeline pipeline) const noexcept
+ {
+ _api.vkCmdBindPipeline(_commandBuffer, pipelineBindPoint, pipeline);
+ }
+
+ void setViewport(uint32_t firstViewport,
+ uint32_t viewportCount,
+ const VkViewport* pViewports) const noexcept
+ {
+ _api.vkCmdSetViewport(
+ _commandBuffer, firstViewport, viewportCount, pViewports);
+ }
+
+ void setScissor(uint32_t firstScissor,
+ uint32_t scissorCount,
+ const VkRect2D* pScissors) const noexcept
+ {
+ _api.vkCmdSetScissor(_commandBuffer, firstScissor, scissorCount, pScissors);
+ }
+
+ void setLineWidth(float lineWidth) const noexcept
+ {
+ _api.vkCmdSetLineWidth(_commandBuffer, lineWidth);
+ }
+
+ void setDepthBias(float depthBiasConstantFactor,
+ float depthBiasClamp,
+ float depthBiasSlopeFactor) const noexcept
+ {
+ _api.vkCmdSetDepthBias(_commandBuffer,
+ depthBiasConstantFactor,
+ depthBiasClamp,
+ depthBiasSlopeFactor);
+ }
+
+ void setBlendConstants(const float blendConstants[4]) const noexcept
+ {
+ _api.vkCmdSetBlendConstants(_commandBuffer, blendConstants);
+ }
+
+ void setDepthBounds(float minDepthBounds, float maxDepthBounds) const noexcept
+ {
+ _api.vkCmdSetDepthBounds(_commandBuffer, minDepthBounds, maxDepthBounds);
+ }
+
+ void setStencilCompareMask(VkStencilFaceFlags faceMask,
+ uint32_t compareMask) const noexcept
+ {
+ _api.vkCmdSetStencilCompareMask(_commandBuffer, faceMask, compareMask);
+ }
+
+ void setStencilWriteMask(VkStencilFaceFlags faceMask,
+ uint32_t writeMask) const noexcept
+ {
+ _api.vkCmdSetStencilWriteMask(_commandBuffer, faceMask, writeMask);
+ }
+
+ void setStencilReference(VkStencilFaceFlags faceMask,
+ uint32_t reference) const noexcept
+ {
+ _api.vkCmdSetStencilReference(_commandBuffer, faceMask, reference);
+ }
+
+ void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint,
+ VkPipelineLayout layout,
+ uint32_t firstSet,
+ uint32_t descriptorSetCount,
+ const VkDescriptorSet* pDescriptorSets,
+ uint32_t dynamicOffsetCount,
+ const uint32_t* pDynamicOffsets) const noexcept
+ {
+ _api.vkCmdBindDescriptorSets(_commandBuffer,
+ pipelineBindPoint,
+ layout,
+ firstSet,
+ descriptorSetCount,
+ pDescriptorSets,
+ dynamicOffsetCount,
+ pDynamicOffsets);
+ }
+
+ void bindIndexBuffer(VkBuffer buffer,
+ VkDeviceSize offset,
+ VkIndexType indexType) const noexcept
+ {
+ _api.vkCmdBindIndexBuffer(_commandBuffer, buffer, offset, indexType);
+ }
+
+ void bindVertexBuffers(uint32_t firstBinding,
+ uint32_t bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets) const noexcept
+ {
+ _api.vkCmdBindVertexBuffers(
+ _commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
+ }
+
+ void waitEvents(
+ uint32_t eventCount,
+ const VkEvent* pEvents,
+ VkPipelineStageFlags srcStageMask,
+ VkPipelineStageFlags dstStageMask,
+ uint32_t memoryBarrierCount,
+ const VkMemoryBarrier* pMemoryBarriers,
+ uint32_t bufferMemoryBarrierCount,
+ const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+ uint32_t imageMemoryBarrierCount,
+ const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept
+ {
+ _api.vkCmdWaitEvents(_commandBuffer,
+ eventCount,
+ pEvents,
+ srcStageMask,
+ dstStageMask,
+ memoryBarrierCount,
+ pMemoryBarriers,
+ bufferMemoryBarrierCount,
+ pBufferMemoryBarriers,
+ imageMemoryBarrierCount,
+ pImageMemoryBarriers);
+ }
+
+ void pipelineBarrier(
+ VkPipelineStageFlags srcStageMask,
+ VkPipelineStageFlags dstStageMask,
+ VkDependencyFlags dependencyFlags,
+ uint32_t memoryBarrierCount,
+ const VkMemoryBarrier* pMemoryBarriers,
+ uint32_t bufferMemoryBarrierCount,
+ const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+ uint32_t imageMemoryBarrierCount,
+ const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept
+ {
+ _api.vkCmdPipelineBarrier(_commandBuffer,
+ srcStageMask,
+ dstStageMask,
+ dependencyFlags,
+ memoryBarrierCount,
+ pMemoryBarriers,
+ bufferMemoryBarrierCount,
+ pBufferMemoryBarriers,
+ imageMemoryBarrierCount,
+ pImageMemoryBarriers);
+ }
+
+ void beginQuery(VkQueryPool queryPool,
+ uint32_t query,
+ VkQueryControlFlags flags) const noexcept
+ {
+ _api.vkCmdBeginQuery(_commandBuffer, queryPool, query, flags);
+ }
+
+ void endQuery(VkQueryPool queryPool, uint32_t query) const noexcept
+ {
+ _api.vkCmdEndQuery(_commandBuffer, queryPool, query);
+ }
+
+ void writeTimestamp(VkPipelineStageFlagBits pipelineStage,
+ VkQueryPool queryPool,
+ uint32_t query) const noexcept
+ {
+ _api.vkCmdWriteTimestamp(_commandBuffer, pipelineStage, queryPool, query);
+ }
+
+ void pushConstants(VkPipelineLayout layout,
+ VkShaderStageFlags stageFlags,
+ uint32_t offset,
+ uint32_t size,
+ const void* pValues) const noexcept
+ {
+ _api.vkCmdPushConstants(
+ _commandBuffer, layout, stageFlags, offset, size, pValues);
+ }
+
+ void executeCommands(uint32_t commandBufferCount,
+ const VkCommandBuffer* pCommandBuffers) const noexcept
+ {
+ _api.vkCmdExecuteCommands(
+ _commandBuffer, commandBufferCount, pCommandBuffers);
+ }
+
+protected:
+ const VulkanApi& _api;
+ VkCommandBuffer _commandBuffer;
+ VkResult _result;
+};
+
+// Top level command scope outside a render pass
+class CommandScope : public CommonCommandScope
+{
+public:
+ CommandScope(const VulkanApi& api,
+ VkCommandBuffer commandBuffer,
+ VkResult result) noexcept
+ : CommonCommandScope{api, commandBuffer, result}
+ {}
+
+ CommandScope(const CommandScope&) = delete;
+ CommandScope& operator=(const CommandScope&) = delete;
+
+ CommandScope(CommandScope&& scope) noexcept
+ : CommonCommandScope{std::forward<CommandScope>(scope)}
+ {}
+
+ CommandScope& operator=(CommandScope&&) = delete;
+
+ ~CommandScope() noexcept
+ {
+ assert(!_commandBuffer); // Buffer must be finished with end()
+ }
+
+ VkResult end() noexcept
+ {
+ if (_commandBuffer) {
+ VkResult r = _api.vkEndCommandBuffer(_commandBuffer);
+ _commandBuffer = {};
+ return r;
+ }
+
+ return VK_NOT_READY;
+ }
+
+ void dispatch(uint32_t groupCountX,
+ uint32_t groupCountY,
+ uint32_t groupCountZ) const noexcept
+ {
+ _api.vkCmdDispatch(_commandBuffer, groupCountX, groupCountY, groupCountZ);
+ }
+
+ void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) const noexcept
+ {
+ _api.vkCmdDispatchIndirect(_commandBuffer, buffer, offset);
+ }
+
+ void copyBuffer(VkBuffer srcBuffer,
+ VkBuffer dstBuffer,
+ uint32_t regionCount,
+ const VkBufferCopy* pRegions) const noexcept
+ {
+ _api.vkCmdCopyBuffer(
+ _commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
+ }
+
+ void copyImage(VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageCopy* pRegions) const noexcept
+ {
+ _api.vkCmdCopyImage(_commandBuffer,
+ srcImage,
+ srcImageLayout,
+ dstImage,
+ dstImageLayout,
+ regionCount,
+ pRegions);
+ }
+
+ void blitImage(VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageBlit* pRegions,
+ VkFilter filter) const noexcept
+ {
+ _api.vkCmdBlitImage(_commandBuffer,
+ srcImage,
+ srcImageLayout,
+ dstImage,
+ dstImageLayout,
+ regionCount,
+ pRegions,
+ filter);
+ }
+
+ void copyBufferToImage(VkBuffer srcBuffer,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkBufferImageCopy* pRegions) const noexcept
+ {
+ _api.vkCmdCopyBufferToImage(_commandBuffer,
+ srcBuffer,
+ dstImage,
+ dstImageLayout,
+ regionCount,
+ pRegions);
+ }
+
+ void copyImageToBuffer(VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkBuffer dstBuffer,
+ uint32_t regionCount,
+ const VkBufferImageCopy* pRegions) const noexcept
+ {
+ _api.vkCmdCopyImageToBuffer(_commandBuffer,
+ srcImage,
+ srcImageLayout,
+ dstBuffer,
+ regionCount,
+ pRegions);
+ }
+
+ void updateBuffer(VkBuffer dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize dataSize,
+ const void* pData) const noexcept
+ {
+ _api.vkCmdUpdateBuffer(
+ _commandBuffer, dstBuffer, dstOffset, dataSize, pData);
+ }
+
+ void fillBuffer(VkBuffer dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize size,
+ uint32_t data) const noexcept
+ {
+ _api.vkCmdFillBuffer(_commandBuffer, dstBuffer, dstOffset, size, data);
+ }
+
+ void clearColorImage(VkImage image,
+ VkImageLayout imageLayout,
+ const VkClearColorValue& color,
+ uint32_t rangeCount,
+ const VkImageSubresourceRange* pRanges) const noexcept
+ {
+ _api.vkCmdClearColorImage(
+ _commandBuffer, image, imageLayout, &color, rangeCount, pRanges);
+ }
+
+ void clearDepthStencilImage(
+ VkImage image,
+ VkImageLayout imageLayout,
+ const VkClearDepthStencilValue& depthStencil,
+ uint32_t rangeCount,
+ const VkImageSubresourceRange* pRanges) const noexcept
+ {
+ _api.vkCmdClearDepthStencilImage(
+ _commandBuffer, image, imageLayout, &depthStencil, rangeCount, pRanges);
+ }
+
+ void resolveImage(VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageResolve* pRegions) const noexcept
+ {
+ _api.vkCmdResolveImage(_commandBuffer,
+ srcImage,
+ srcImageLayout,
+ dstImage,
+ dstImageLayout,
+ regionCount,
+ pRegions);
+ }
+
+ void setEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept
+ {
+ _api.vkCmdSetEvent(_commandBuffer, event, stageMask);
+ }
+
+ void resetEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept
+ {
+ _api.vkCmdResetEvent(_commandBuffer, event, stageMask);
+ }
+
+ void resetQueryPool(VkQueryPool queryPool,
+ uint32_t firstQuery,
+ uint32_t queryCount) const noexcept
+ {
+ _api.vkCmdResetQueryPool(_commandBuffer, queryPool, firstQuery, queryCount);
+ }
+
+ void copyQueryPoolResults(VkQueryPool queryPool,
+ uint32_t firstQuery,
+ uint32_t queryCount,
+ VkBuffer dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize stride,
+ VkQueryResultFlags flags) const noexcept
+ {
+ _api.vkCmdCopyQueryPoolResults(_commandBuffer,
+ queryPool,
+ firstQuery,
+ queryCount,
+ dstBuffer,
+ dstOffset,
+ stride,
+ flags);
+ }
+
+ SYBOK_NODISCARD
+ RenderCommandScope beginRenderPass(
+ const VkRenderPassBeginInfo& renderPassBegin,
+ VkSubpassContents contents) const noexcept;
+};
+
+class RenderCommandScope : public CommonCommandScope
+{
+public:
+ RenderCommandScope(const VulkanApi& api,
+ VkCommandBuffer commandBuffer) noexcept
+ : CommonCommandScope{api, commandBuffer, VK_SUCCESS}
+ {}
+
+ RenderCommandScope(const RenderCommandScope&) = delete;
+ RenderCommandScope& operator=(const RenderCommandScope&) = delete;
+
+ RenderCommandScope(RenderCommandScope&& scope) noexcept
+ : CommonCommandScope{std::forward<RenderCommandScope>(scope)}
+ {}
+
+ RenderCommandScope& operator=(RenderCommandScope&&) = delete;
+
+ ~RenderCommandScope() noexcept { _api.vkCmdEndRenderPass(_commandBuffer); }
+
+ void draw(uint32_t vertexCount,
+ uint32_t instanceCount,
+ uint32_t firstVertex,
+ uint32_t firstInstance) const noexcept
+ {
+ _api.vkCmdDraw(
+ _commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
+ }
+
+ void drawIndexed(uint32_t indexCount,
+ uint32_t instanceCount,
+ uint32_t firstIndex,
+ int32_t vertexOffset,
+ uint32_t firstInstance) const noexcept
+ {
+ _api.vkCmdDrawIndexed(_commandBuffer,
+ indexCount,
+ instanceCount,
+ firstIndex,
+ vertexOffset,
+ firstInstance);
+ }
+
+ void drawIndirect(VkBuffer buffer,
+ VkDeviceSize offset,
+ uint32_t drawCount,
+ uint32_t stride) const noexcept
+ {
+ _api.vkCmdDrawIndirect(_commandBuffer, buffer, offset, drawCount, stride);
+ }
+
+ void drawIndexedIndirect(VkBuffer buffer,
+ VkDeviceSize offset,
+ uint32_t drawCount,
+ uint32_t stride) const noexcept
+ {
+ _api.vkCmdDrawIndexedIndirect(
+ _commandBuffer, buffer, offset, drawCount, stride);
+ }
+
+ void clearAttachments(uint32_t attachmentCount,
+ const VkClearAttachment& attachments,
+ uint32_t rectCount,
+ const VkClearRect* pRects) const noexcept
+ {
+ _api.vkCmdClearAttachments(
+ _commandBuffer, attachmentCount, &attachments, rectCount, pRects);
+ }
+
+ void nextSubpass(VkSubpassContents contents) const noexcept
+ {
+ _api.vkCmdNextSubpass(_commandBuffer, contents);
+ }
+};
+
+inline CommandScope
+VulkanApi::beginCommandBuffer(
+ VkCommandBuffer commandBuffer,
+ const VkCommandBufferBeginInfo beginInfo) const noexcept
+{
+ if (const VkResult r = vkBeginCommandBuffer(commandBuffer, &beginInfo)) {
+ return {*this, nullptr, r};
+ }
+
+ return {*this, commandBuffer, VK_SUCCESS};
+}
+
+inline RenderCommandScope
+CommandScope::beginRenderPass(const VkRenderPassBeginInfo& renderPassBegin,
+ VkSubpassContents contents) const noexcept
+{
+ _api.vkCmdBeginRenderPass(_commandBuffer, &renderPassBegin, contents);
+
+ return {_api, _commandBuffer};
+}
+
+inline MappedMemory::~MappedMemory() noexcept
+{
+ if (_api && _memory) {
+ _api->vkUnmapMemory(_device, _memory);
+ }
+}
+
+} // namespace sk
+
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#endif // SYBOK_HPP