aboutsummaryrefslogtreecommitdiff
path: root/subprojects/d2tk/pugl
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2020-04-08 22:31:47 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2020-04-08 22:31:47 +0200
commit186d26b69d6de8ba6f8e0d71bdb9e3aedfa756c7 (patch)
tree30106f0be192ea2a26c6cc3766ec5b74a1dad820 /subprojects/d2tk/pugl
parentda08fb1a37b07f0e923c2cdbfd3cae72f77a1680 (diff)
parentfb2fde4db458f7b82b96cc5021fce3710e72f036 (diff)
downloadsynthpod-186d26b69d6de8ba6f8e0d71bdb9e3aedfa756c7.tar.xz
Merge commit 'fb2fde4db458f7b82b96cc5021fce3710e72f036' into feature-d2tk-update
Diffstat (limited to 'subprojects/d2tk/pugl')
-rw-r--r--subprojects/d2tk/pugl/.clang-format127
-rw-r--r--subprojects/d2tk/pugl/.clang-tidy16
-rw-r--r--subprojects/d2tk/pugl/.gitattributes1
-rw-r--r--subprojects/d2tk/pugl/.gitignore2
-rw-r--r--subprojects/d2tk/pugl/.gitlab-ci.yml118
-rw-r--r--subprojects/d2tk/pugl/.gitmodules3
-rw-r--r--subprojects/d2tk/pugl/AUTHORS20
-rw-r--r--subprojects/d2tk/pugl/COPYING2
-rw-r--r--subprojects/d2tk/pugl/README.md114
-rw-r--r--subprojects/d2tk/pugl/doc/footer.html20
-rw-r--r--subprojects/d2tk/pugl/doc/header.html49
-rw-r--r--subprojects/d2tk/pugl/doc/layout.xml193
-rw-r--r--subprojects/d2tk/pugl/doc/mainpage.md73
-rw-r--r--subprojects/d2tk/pugl/doc/reference.doxygen.in (renamed from subprojects/d2tk/pugl/Doxyfile.in)233
-rw-r--r--subprojects/d2tk/pugl/doc/style.css808
-rw-r--r--subprojects/d2tk/pugl/examples/cube_view.h82
-rw-r--r--subprojects/d2tk/pugl/examples/demo_utils.h175
-rw-r--r--subprojects/d2tk/pugl/examples/glad/glad.c1138
-rw-r--r--subprojects/d2tk/pugl/examples/glad/glad.h2129
-rw-r--r--subprojects/d2tk/pugl/examples/glad/khrplatform.h290
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_cairo_demo.c270
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_embed_demo.c366
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_gl3_demo.c432
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_print_events.c79
-rw-r--r--subprojects/d2tk/pugl/examples/pugl_window_demo.c252
-rw-r--r--subprojects/d2tk/pugl/examples/shader_utils.h97
-rw-r--r--subprojects/d2tk/pugl/pugl.pc.in7
-rw-r--r--subprojects/d2tk/pugl/pugl/cairo_gl.h106
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/implementation.c467
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/implementation.h76
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/mac.h65
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/mac.m1200
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/mac_cairo.m155
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/mac_gl.m177
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/mac_stub.m95
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/types.h113
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/win.c1084
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/win.h141
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/win_cairo.c178
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/win_gl.c308
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/x11.c1218
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/x11.h83
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/x11_cairo.c169
-rw-r--r--subprojects/d2tk/pugl/pugl/detail/x11_gl.c216
-rw-r--r--subprojects/d2tk/pugl/pugl/gl.h1
-rw-r--r--subprojects/d2tk/pugl/pugl/glu.h3
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl.h1475
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl.hpp34
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_cairo.h49
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_cairo_backend.h (renamed from subprojects/d2tk/pugl/pugl/glew.h)21
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_gl.h60
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_gl_backend.h23
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_internal.h273
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_osx.m746
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_stub.h103
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_stub_backend.h23
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_win.cpp704
-rw-r--r--subprojects/d2tk/pugl/pugl/pugl_x11.c810
-rw-r--r--subprojects/d2tk/pugl/pugl_cairo_test.c205
-rw-r--r--subprojects/d2tk/pugl/pugl_test.c261
-rw-r--r--subprojects/d2tk/pugl/resources/Info.plist.in20
-rw-r--r--subprojects/d2tk/pugl/resources/pugl.ipe293
-rw-r--r--subprojects/d2tk/pugl/resources/pugl.pngbin0 -> 2641 bytes
-rw-r--r--subprojects/d2tk/pugl/resources/pugl.svg83
-rw-r--r--subprojects/d2tk/pugl/shaders/rect.frag35
-rw-r--r--subprojects/d2tk/pugl/shaders/rect.vert34
-rw-r--r--subprojects/d2tk/pugl/test/test_redisplay.c132
-rw-r--r--subprojects/d2tk/pugl/test/test_show_hide.c147
-rw-r--r--subprojects/d2tk/pugl/test/test_timer.c160
-rw-r--r--subprojects/d2tk/pugl/test/test_update.c124
-rw-r--r--subprojects/d2tk/pugl/test/test_utils.h256
-rwxr-xr-xsubprojects/d2tk/pugl/wafbin97489 -> 709 bytes
-rw-r--r--subprojects/d2tk/pugl/wscript499
73 files changed, 15807 insertions, 3714 deletions
diff --git a/subprojects/d2tk/pugl/.clang-format b/subprojects/d2tk/pugl/.clang-format
new file mode 100644
index 00000000..b7886761
--- /dev/null
+++ b/subprojects/d2tk/pugl/.clang-format
@@ -0,0 +1,127 @@
+---
+# Language: Cpp
+# BasedOnStyle: Mozilla
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: true
+AlignConsecutiveDeclarations: true
+AlignEscapedNewlines: Left
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: TopLevel
+AlwaysBreakAfterReturnType: TopLevel
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: true
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: true
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: true
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeComma
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeComma
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 1
+IncludeIsMainRegex: '(Test)?$'
+IndentCaseLabels: false
+IndentPPDirectives: AfterHash
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 4
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakAssignment: 100
+PenaltyBreakBeforeFirstCallParameter: 100
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 0
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: true
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+StatementMacros:
+ - PUGL_API
+ - PUGL_DEPRECATED_BY
+ - PUGL_UNUSED
+TabWidth: 4
+UseTab: ForIndentation
+...
+
diff --git a/subprojects/d2tk/pugl/.clang-tidy b/subprojects/d2tk/pugl/.clang-tidy
new file mode 100644
index 00000000..055d63b3
--- /dev/null
+++ b/subprojects/d2tk/pugl/.clang-tidy
@@ -0,0 +1,16 @@
+Checks: >
+ *,
+ -*magic-numbers,
+ -*uppercase-literal-suffix,
+ -android-cloexec-fopen,
+ -bugprone-suspicious-string-compare,
+ -cert-flp30-c,
+ -clang-analyzer-alpha.*,
+ -clang-analyzer-security.FloatLoopCounter,
+ -hicpp-multiway-paths-covered,
+ -hicpp-signed-bitwise,
+ -llvm-header-guard,
+ -readability-else-after-return
+WarningsAsErrors: ''
+HeaderFilterRegex: 'pugl/.*|test/.*'
+FormatStyle: file
diff --git a/subprojects/d2tk/pugl/.gitattributes b/subprojects/d2tk/pugl/.gitattributes
new file mode 100644
index 00000000..32967c10
--- /dev/null
+++ b/subprojects/d2tk/pugl/.gitattributes
@@ -0,0 +1 @@
+waflib/* linguist-vendored
diff --git a/subprojects/d2tk/pugl/.gitignore b/subprojects/d2tk/pugl/.gitignore
index e5116427..dad71c32 100644
--- a/subprojects/d2tk/pugl/.gitignore
+++ b/subprojects/d2tk/pugl/.gitignore
@@ -1,3 +1,5 @@
.waf*/
build/
.lock-waf*
+__pycache__
+*.pyc
diff --git a/subprojects/d2tk/pugl/.gitlab-ci.yml b/subprojects/d2tk/pugl/.gitlab-ci.yml
new file mode 100644
index 00000000..29dc8bea
--- /dev/null
+++ b/subprojects/d2tk/pugl/.gitlab-ci.yml
@@ -0,0 +1,118 @@
+stages:
+ - build
+ - deploy
+
+variables:
+ GIT_SUBMODULE_STRATEGY: normal
+
+.build_template: &build_definition
+ stage: build
+
+arm32_dbg:
+ <<: *build_definition
+ image: lv2plugin/debian-arm32
+ script: python ./waf configure build -dsT --no-coverage
+ variables:
+ CC: "arm-linux-gnueabihf-gcc"
+ CXX: "arm-linux-gnueabihf-g++"
+
+arm32_rel:
+ <<: *build_definition
+ image: lv2plugin/debian-arm32
+ script: python ./waf configure build -sT --no-coverage
+ variables:
+ CC: "arm-linux-gnueabihf-gcc"
+ CXX: "arm-linux-gnueabihf-g++"
+
+arm64_dbg:
+ <<: *build_definition
+ image: lv2plugin/debian-arm64
+ script: python ./waf configure build -dsT --no-coverage
+ variables:
+ CC: "aarch64-linux-gnu-gcc"
+ CXX: "aarch64-linux-gnu-g++"
+
+arm64_rel:
+ <<: *build_definition
+ image: lv2plugin/debian-arm64
+ script: python ./waf configure build -sT --no-coverage
+ variables:
+ CC: "aarch64-linux-gnu-gcc"
+ CXX: "aarch64-linux-gnu-g++"
+
+x64_dbg:
+ <<: *build_definition
+ image: lv2plugin/debian-x64
+ script: python ./waf configure build -dsT --no-coverage --docs
+ artifacts:
+ paths:
+ - build/doc
+
+x64_rel:
+ <<: *build_definition
+ image: lv2plugin/debian-x64
+ script: python ./waf configure build -sT --no-coverage
+
+mingw32_dbg:
+ <<: *build_definition
+ image: lv2plugin/debian-mingw32
+ script: python ./waf configure build -dsT --no-coverage --target=win32
+ variables:
+ CC: "i686-w64-mingw32-gcc"
+ CXX: "i686-w64-mingw32-g++"
+
+mingw32_rel:
+ <<: *build_definition
+ image: lv2plugin/debian-mingw32
+ script: python ./waf configure build -sT --no-coverage --target=win32
+ variables:
+ CC: "i686-w64-mingw32-gcc"
+ CXX: "i686-w64-mingw32-g++"
+
+mingw64_dbg:
+ <<: *build_definition
+ image: lv2plugin/debian-mingw64
+ script: python ./waf configure build -dsT --no-coverage --target=win32
+ variables:
+ CC: "x86_64-w64-mingw32-gcc"
+ CXX: "x86_64-w64-mingw32-g++"
+
+mingw64_rel:
+ <<: *build_definition
+ image: lv2plugin/debian-mingw64
+ script: python ./waf configure build -sT --no-coverage --target=win32
+ variables:
+ CC: "x86_64-w64-mingw32-gcc"
+ CXX: "x86_64-w64-mingw32-g++"
+
+mac_dbg:
+ <<: *build_definition
+ script: python ./waf configure build -dsT --no-coverage
+ tags: [macos]
+
+mac_rel:
+ <<: *build_definition
+ script: python ./waf configure build -sT --no-coverage
+ tags: [macos]
+
+win_dbg:
+ <<: *build_definition
+ script:
+ - python ./waf configure build -dT --no-coverage
+ tags: [windows,msvc,python]
+
+win_rel:
+ <<: *build_definition
+ script: python ./waf configure build -T --no-coverage
+ tags: [windows,msvc,python]
+
+pages:
+ stage: deploy
+ script: mv build/doc/html/ public/
+ dependencies:
+ - x64_dbg
+ artifacts:
+ paths:
+ - public
+ only:
+ - master
diff --git a/subprojects/d2tk/pugl/.gitmodules b/subprojects/d2tk/pugl/.gitmodules
new file mode 100644
index 00000000..cc8b569f
--- /dev/null
+++ b/subprojects/d2tk/pugl/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "waflib"]
+ path = waflib
+ url = ../../drobilla/autowaf.git
diff --git a/subprojects/d2tk/pugl/AUTHORS b/subprojects/d2tk/pugl/AUTHORS
index 5625baa4..1470491c 100644
--- a/subprojects/d2tk/pugl/AUTHORS
+++ b/subprojects/d2tk/pugl/AUTHORS
@@ -1,11 +1,11 @@
-Author:
- David Robillard <d@drobilla.net>
+Pugl is primarily written and maintained by David Robillard <d@drobilla.net>
+with contributions from (in increasing chronological order):
-Original GLX inspiration, portability fixes:
- Ben Loftis
-
-Various fixes and improvements:
- Robin Gareus <robin@gareus.org>
-
-UTF-8 and Windows event work:
- Erik Åldstedt Sund <erikalds@gmail.com>
+Ben Loftis <ben@harrisonconsoles.com>
+Robin Gareus <robin@gareus.org>
+Erik Åldstedt Sund <erikalds@gmail.com>
+Hanspeter Portner <dev@open-music-kontrollers.ch>
+Stefan Westerfeld <stefan@space.twc.de>
+Jordan Halase <jordan@halase.me>
+Oliver Schmidt <oliver@luced.de>
+Zoë Sparks <zoe@milky.flowers> \ No newline at end of file
diff --git a/subprojects/d2tk/pugl/COPYING b/subprojects/d2tk/pugl/COPYING
index e1e203dd..4a287b92 100644
--- a/subprojects/d2tk/pugl/COPYING
+++ b/subprojects/d2tk/pugl/COPYING
@@ -1,4 +1,4 @@
-Copyright 2011-2014 David Robillard <http://drobilla.net>
+Copyright 2011-2020 David Robillard <http://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
diff --git a/subprojects/d2tk/pugl/README.md b/subprojects/d2tk/pugl/README.md
index 77809d80..ae9c420e 100644
--- a/subprojects/d2tk/pugl/README.md
+++ b/subprojects/d2tk/pugl/README.md
@@ -1,28 +1,108 @@
-PUGL
+Pugl
====
-Pugl is a minimal portable API for GUIs which supports embedding and is
-suitable for use in plugins. It works on X11, Mac OS X, and Windows. GUIs can
-be drawn with OpenGL or Cairo.
+Pugl (PlUgin Graphics Library) is a minimal portable API for GUIs which is
+suitable for use in plugins. It works on X11, MacOS, and Windows, and
+optionally supports OpenGL and Cairo graphics contexts.
-Pugl is vaguely similar to GLUT, but with some significant distinctions:
+Pugl is vaguely similar to libraries like GLUT and GLFW, but with some
+distinguishing features:
- * Minimal in scope, providing only what is necessary to draw and receive
- keyboard and mouse input.
+ * Minimal in scope, providing only a thin interface to isolate
+ platform-specific details from applications.
- * No reliance on static data whatsoever, so the API can be used in plugins or
- multiple independent parts of a program.
+ * Zero dependencies, aside from standard system libraries.
- * Single implementation, which is small, liberally licensed Free / Open Source
- Software, and suitable for direct inclusion in programs if avoiding a
- library dependency is desired.
+ * Support for embedding in native windows, for example as a plugin or
+ component within a larger application that is not based on Pugl.
- * Support for embedding in other windows, so Pugl code can draw to a widget
- inside a larger GUI.
+ * Simple and extensible event-based API that makes dispatching in application
+ or toolkit code easy with minimal boilerplate.
- * More complete support for keyboard input, including additional "special"
- keys, modifiers, and support for detecting individual modifier key presses.
+ * Suitable not only for continuously rendering applications like games, but
+ also event-driven applications that only draw when necessary.
-For more information, see <http://drobilla.net/software/pugl>.
+ * Explicit context and no static data whatsoever, so that several instances
+ can be used within a single program at once.
+
+ * Small, liberally licensed Free Software implementation that is suitable for
+ vendoring and/or static linking. Pugl can be installed as a library, or
+ used by simply copying the headers into a project.
+
+Stability
+---------
+
+Pugl is currently being developed towards a long-term stable API. For the time
+being, however, the API may break occasionally. Please report any relevant
+feedback, or file feature requests, so that we can ensure that the released API
+is stable for as long as possible.
+
+Distribution
+------------
+
+Pugl is designed for flexible distribution. It can be used by simply including
+the source code, or installed and linked against as a static or shared library.
+Static linking or direct inclusion is a good idea for plugins that will be
+distributed as binaries to avoid dependency problems.
+
+If you are including the code, please use a submodule so that suitable changes
+can be merged upstream to keep fragmentation to a minimum.
+
+When installed, Pugl is split into different libraries to keep dependencies
+minimal. The core implementation is separate from graphics backends:
+
+ * The core implementation for a particular platform is in one library:
+ `pugl_x11`, `pugl_mac`, or `pugl_win`. This does not depend on backends or
+ their dependencies.
+
+ * Backends for platforms are in separate libraries, which depend on the core:
+ `pugl_x11_cairo`, `pugl_x11_gl`, `pugl_mac_cairo`, and so on.
+
+Applications must link against the core and at least one backend. Normally,
+this can be achieved by simply depending on the package `pugl-gl-0` or
+`pugl-cairo-0`. Though it is possible to compile everything into a monolithic
+library, distributions should retain this separation so that GL applications
+don't depend on Cairo and its dependencies, or vice-versa.
+
+Distributions are encouraged to include static libraries if possible so that
+developers can build portable plugin binaries.
+
+Testing
+-------
+
+There are a few unit tests included which can be run with `python waf test
+--gui-tests`, but unfortunately manual testing is still required.
+
+Several example programs are included that serve as both manual tests and
+demonstrations:
+
+ * `pugl_embed_demo` shows a view embedded in another, and also tests
+ requesting attention (which happens after 5 seconds), keyboard focus
+ (switched by pressing tab), view moving (with the arrow keys), and view
+ resizing (with the arrow keys while shift is held). This program uses only
+ very old OpenGL and should work on any system.
+
+ * `pugl_window_demo` demonstrates multiple top-level windows.
+
+ * `pugl_gl3_demo` demonstrates using more modern OpenGL where dynamic loading
+ and shaders are required. It can also be used to test performance by
+ passing the number of rectangles to draw on the command line.
+
+ * `pugl_cairo_demo` demonstrates using Cairo on top of the native windowing
+ system (without OpenGL), and partial redrawing.
+
+ * `pugl_print_events` is a utility that prints all received events to the
+ console in a human readable format.
+
+All example programs support several command line options to control various
+behaviours, see the output of `--help` for details. Please file an issue if
+any of these programs do not work as expected on your system.
+
+Documentation
+-------------
+
+The [API reference](https://lv2.gitlab.io/pugl/) for the latest master is
+available online, and can also be built from the source code by configuring
+with `--docs`.
-- David Robillard <d@drobilla.net>
diff --git a/subprojects/d2tk/pugl/doc/footer.html b/subprojects/d2tk/pugl/doc/footer.html
new file mode 100644
index 00000000..0dc69197
--- /dev/null
+++ b/subprojects/d2tk/pugl/doc/footer.html
@@ -0,0 +1,20 @@
+<!-- HTML footer for doxygen 1.8.15-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+ <ul>
+ $navpath
+ <li class="footer">$generatedby
+ <a href="http://www.doxygen.org/index.html">Doxygen $doxygenversion</li>
+ </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<div id="footer">
+ <address class="footer">$generatedby
+ <a href="http://www.doxygen.org/">Doxygen</a> $doxygenversion
+ </address>
+</div>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/subprojects/d2tk/pugl/doc/header.html b/subprojects/d2tk/pugl/doc/header.html
new file mode 100644
index 00000000..54c25b06
--- /dev/null
+++ b/subprojects/d2tk/pugl/doc/header.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+ <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+ <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+ $extrastylesheet
+ </head>
+ <body>
+ <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+ <!--BEGIN TITLEAREA-->
+ <div id="titlearea">
+ <div id="header">
+ <div id="titlebox">
+ <!--BEGIN PROJECT_LOGO-->
+ <div id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></div>
+ <!--END PROJECT_LOGO-->
+ <!--BEGIN PROJECT_NAME-->
+ <h1 id="title">$projectname</h1>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <div id="shortdesc">$projectbrief</div>
+ <!--END PROJECT_BRIEF-->
+ </div>
+ <div id="metabox">
+ <table id="meta">
+ <!--BEGIN PROJECT_NUMBER-->
+ <tr><th>Version</th><td>$projectnumber</td></tr>
+ <!--END PROJECT_NUMBER-->
+ </table>
+ </div>
+ </div>
+ </div>
+ <!--END TITLEAREA-->
+ <!-- end header part -->
+
+ <!-- Fake static menu from Doxygen 1.8.15 -->
+ <div id="staticnavrow" class="tabs">
+ <ul class="tablist">
+ <li><a href="index.html"><span>Main&#160;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="namespaces.html"><span>Namespaces</span></a></li>
+ <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
+ <li><a href="functions.html"><span>Symbols</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul>
+ </div>
diff --git a/subprojects/d2tk/pugl/doc/layout.xml b/subprojects/d2tk/pugl/doc/layout.xml
new file mode 100644
index 00000000..18893027
--- /dev/null
+++ b/subprojects/d2tk/pugl/doc/layout.xml
@@ -0,0 +1,193 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.13 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title=""/>
+ <tab type="pages" visible="yes" title="" intro=""/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="files" visible="yes" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <detaileddescription title=""/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ </directory>
+</doxygenlayout>
diff --git a/subprojects/d2tk/pugl/doc/mainpage.md b/subprojects/d2tk/pugl/doc/mainpage.md
new file mode 100644
index 00000000..aa6f925a
--- /dev/null
+++ b/subprojects/d2tk/pugl/doc/mainpage.md
@@ -0,0 +1,73 @@
+This is the API documentation for Pugl.
+This documentation is based around the [C API](@ref pugl_api),
+there is also a [C++ API](@ref pugl) in the `pugl` namespace.
+
+The Pugl API revolves around two main objects:
+the [World](@ref world) and the [View](@ref view).
+An application creates a single world to manage top-level state,
+then creates one or more views to display.
+
+## World
+
+The [World](@ref world) contains all top-level state,
+and manages views and the event loop.
+
+A world must be [created](@ref puglNewWorld) before any views,
+and it must outlive all views.
+
+## View
+
+A [View](@ref view) is a drawable region that receives events.
+
+Creating a visible view is a multi-step process.
+When a new view is [created](@ref puglNewView),
+it does not yet represent a real system view or window.
+To display, it must first have a [backend](@ref puglSetBackend)
+and [event handler](@ref puglSetEventFunc) set,
+and be configured by [setting hints](@ref puglSetViewHint)
+and optionally [adjusting the frame](@ref frame).
+
+The [Backend](@ref PuglBackend) controls drawing for a view.
+Pugl includes [Cairo](@ref cairo) and [OpenGL](@ref gl) backends,
+as well as a [stub](@ref stub) backend that creates a native window with no drawing context.
+
+
+Once the view is configured,
+it can be [realized](@ref puglRealize) and [shown](@ref puglShowWindow).
+By default a view will correspond to a top-level system window.
+To create a view within another window,
+it must have a [parent window set](@ref puglSetParentWindow) before being created.
+
+
+## Events
+
+[Events](@ref events) are sent to a view when it has received user input or must be drawn.
+
+Events are handled by the [event handler](@ref PuglEventFunc) set during initialisation.
+This function is called whenever something happens that the view must respond to.
+This includes user interaction like mouse and keyboard input,
+and system events like window resizing and exposure.
+
+## Event Loop
+
+The event loop is driven by repeatedly calling #puglUpdate which processes events from the window system,
+and dispatches them to views when necessary.
+
+Typically, a plugin calls #puglUpdate with timeout 0 in some callback driven by the host.
+A program can use whatever timeout is appropriate:
+event-driven applications may wait forever,
+or for continuous animation,
+use a timeout that is a significant fraction of the frame period
+(with enough time left over to render).
+
+Redrawing can be requested by calling #puglPostRedisplay or #puglPostRedisplayRect,
+which post expose events to the queue.
+Note, however, that this will not wake up a blocked #puglUpdate call on MacOS
+(which does not handle drawing via events).
+For continuous redrawing, call #puglPostRedisplay when a #PUGL_UPDATE event is received.
+This event is sent before views are redrawn,
+so can be used as a hook to expand the update region right before the view is exposed.
+
+## Error Handling
+
+Most functions return a [Status](@ref status) which should be checked to detect failure.
diff --git a/subprojects/d2tk/pugl/Doxyfile.in b/subprojects/d2tk/pugl/doc/reference.doxygen.in
index 59e33311..1357fe4a 100644
--- a/subprojects/d2tk/pugl/Doxyfile.in
+++ b/subprojects/d2tk/pugl/doc/reference.doxygen.in
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.12
+# Doxyfile 1.8.15
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -17,11 +17,11 @@
# Project related configuration options
#---------------------------------------------------------------------------
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
@@ -44,7 +44,7 @@ PROJECT_NUMBER = @PUGL_VERSION@
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
-PROJECT_BRIEF =
+PROJECT_BRIEF = "A minimal portable API for embeddable GUIs"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY = doc
+OUTPUT_DIRECTORY = .
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION = None
+
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@@ -226,7 +234,12 @@ TAB_SIZE = 4
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
ALIASES =
@@ -264,17 +277,26 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is
+# Fortran), use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
@@ -285,7 +307,7 @@ EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@@ -327,7 +349,7 @@ BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
@@ -357,7 +379,7 @@ DISTRIBUTE_GROUP_DOC = NO
# is disabled and one has to add nested compounds explicitly via \ingroup.
# The default value is: NO.
-GROUP_NESTED_COMPOUNDS = YES
+GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
@@ -663,14 +685,14 @@ SHOW_USED_FILES = YES
# (if specified).
# The default value is: YES.
-SHOW_FILES = NO
+SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
# page. This will remove the Namespaces entry from the Quick Index and from the
# Folder Tree View (if specified).
# The default value is: YES.
-SHOW_NAMESPACES = NO
+SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
@@ -693,12 +715,12 @@ FILE_VERSION_FILTER =
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
-LAYOUT_FILE =
+LAYOUT_FILE = @PUGL_SRCDIR@/doc/layout.xml
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -743,7 +765,8 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation.
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = YES
@@ -780,12 +803,13 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = pugl
+INPUT = @PUGL_SRCDIR@/pugl/ \
+ @PUGL_SRCDIR@/doc/mainpage.md
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
@@ -803,9 +827,9 @@ INPUT_ENCODING = UTF-8
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
-# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
-FILE_PATTERNS =
+FILE_PATTERNS = *.h *.hpp
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
@@ -929,7 +953,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE =
+USE_MDFILE_AS_MAINPAGE = @PUGL_SRCDIR@/doc/mainpage.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -958,7 +982,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
+# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@@ -967,7 +991,7 @@ REFERENCED_BY_RELATION = NO
# all documented entities called/used by that function will be listed.
# The default value is: NO.
-REFERENCES_RELATION = NO
+REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
@@ -985,17 +1009,17 @@ REFERENCES_LINK_SOURCE = YES
# The default value is: YES.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
-SOURCE_TOOLTIPS = YES
+SOURCE_TOOLTIPS = NO
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
+# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@@ -1085,7 +1109,7 @@ HTML_FILE_EXTENSION = .html
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_HEADER =
+HTML_HEADER = @PUGL_SRCDIR@/doc/header.html
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1095,7 +1119,7 @@ HTML_HEADER =
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_FOOTER =
+HTML_FOOTER = @PUGL_SRCDIR@/doc/footer.html
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of
@@ -1107,7 +1131,7 @@ HTML_FOOTER =
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_STYLESHEET =
+HTML_STYLESHEET = @PUGL_SRCDIR@/doc/style.css
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
@@ -1135,13 +1159,13 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_COLORSTYLE_HUE = 130
+HTML_COLORSTYLE_HUE = 160
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
@@ -1149,7 +1173,7 @@ HTML_COLORSTYLE_HUE = 130
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_COLORSTYLE_SAT = 30
+HTML_COLORSTYLE_SAT = 100
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
@@ -1160,7 +1184,7 @@ HTML_COLORSTYLE_SAT = 30
# Minimum value: 40, maximum value: 240, default value: 80.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_COLORSTYLE_GAMMA = 100
+HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
@@ -1171,13 +1195,24 @@ HTML_COLORSTYLE_GAMMA = 100
HTML_TIMESTAMP = NO
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via Javascript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have Javascript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = NO
+
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_DYNAMIC_SECTIONS = YES
+HTML_DYNAMIC_SECTIONS = NO
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
@@ -1194,13 +1229,13 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# environment (see: https://developer.apple.com/xcode/), introduced with OSX
+# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1239,7 +1274,7 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
@@ -1315,7 +1350,7 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1323,7 +1358,7 @@ QHP_NAMESPACE =
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1332,7 +1367,7 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1340,7 +1375,7 @@ QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1348,7 +1383,7 @@ QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
@@ -1389,7 +1424,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
-DISABLE_INDEX = YES
+DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag
@@ -1416,7 +1451,7 @@ GENERATE_TREEVIEW = NO
# Minimum value: 0, maximum value: 20, default value: 4.
# This tag requires that the tag GENERATE_HTML is set to YES.
-ENUM_VALUES_PER_LINE = 1
+ENUM_VALUES_PER_LINE = 0
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
# to set the initial width (in pixels) of the frame in which the tree is shown.
@@ -1441,7 +1476,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@@ -1453,7 +1488,7 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
+# https://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@@ -1480,8 +1515,8 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
@@ -1542,7 +1577,7 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
+# Xapian (see: https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1555,7 +1590,7 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1607,21 +1642,34 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: \makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = \makeindex
+
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
@@ -1742,7 +1790,7 @@ LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1756,6 +1804,14 @@ LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -1795,9 +1851,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@@ -1806,8 +1862,8 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
@@ -1893,6 +1949,13 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@@ -1925,9 +1988,9 @@ DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sf.net) file that captures the
-# structure of the code including all documentation. Note that this feature is
-# still experimental and incomplete at the moment.
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -1987,7 +2050,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
@@ -1995,7 +2058,7 @@ MACRO_EXPANSION = NO
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
@@ -2027,7 +2090,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED =
+PREDEFINED = PUGL_API PUGL_DISABLE_DEPRECATED
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@@ -2094,12 +2157,6 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
@@ -2113,15 +2170,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = NO
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2349,6 +2397,11 @@ DIAFILE_DIRS =
PLANTUML_JAR_PATH =
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
diff --git a/subprojects/d2tk/pugl/doc/style.css b/subprojects/d2tk/pugl/doc/style.css
new file mode 100644
index 00000000..28f0519d
--- /dev/null
+++ b/subprojects/d2tk/pugl/doc/style.css
@@ -0,0 +1,808 @@
+body {
+ background: #FFF;
+ color: #222;
+ font-style: normal;
+ line-height: 1.6em;
+ margin-left: auto;
+ margin-right: auto;
+ padding: 1em;
+ max-width: 60em;
+ font-family: "SF Pro Text", Verdana, "DejaVu Sans", sans-serif;
+ text-rendering: optimizeLegibility;
+}
+
+h1 {
+ font-size: 1.68em;
+ font-weight: 500;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ line-height: 2em;
+ margin: 0 0 0.25em 0;
+}
+
+h2 {
+ line-height: 1.68em;
+ font-size: 1.41em;
+ font-weight: 600;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ margin: 1.25em 0 0.5em 0;
+}
+
+h3 {
+ line-height: 1.41em;
+ font-size: 1.18em;
+ font-weight: 600;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ margin: 1.25em 0 0.5em 0;
+}
+
+h4 {
+ line-height: 1.18em;
+ font-size: 1em;
+ font-weight: 600;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ margin: 1.25em 0 0.5em 0;
+}
+
+h5, h6 {
+ font-size: 0.7em;
+ font-weight: 600;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ margin: 1.25em 0 0.5em 0;
+}
+
+a {
+ color: #546E00;
+ text-decoration: none;
+}
+
+h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
+ color: #444;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+h1 a:link, h2 a:link, h3 a:link, h4 a:link, h5 a:link, h6 a:link {
+ color: #444;
+}
+
+h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {
+ color: #444;
+}
+
+p {
+ margin: 0.5em 0 0.5em 0;
+}
+
+dt {
+ font-weight: 600;
+}
+
+dd {
+ margin-left: 2em;
+}
+
+caption {
+ font-weight: 700;
+}
+
+.title, #projectname {
+ line-height: 1.0125em;
+ margin: 0.75em 0 0 0;
+}
+
+.titlearea .header .titlebox, #projectname {
+ font-size: 1.68em;
+ font-weight: 400;
+ margin-bottom: 0.25em;
+ margin-top: 0;
+}
+
+#header {
+ padding: 0 0 0.5em 0;
+ border-bottom: 1px solid #EEE;
+}
+
+.header .headertitle .title {
+ line-height: 1.68em;
+ font-size: 1.68em;
+ font-weight: 600;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+}
+
+.ingroups {
+ display: none;
+}
+
+.title .ingroups a {
+ font-size: small;
+ margin-left: 1em;
+}
+
+#titlebox, #metabox {
+ display: inline-block;
+}
+
+#titlebox {
+ display: inline-block;
+ width: 75%;
+ left: 0;
+ top: 0;
+}
+
+#title {
+ margin-bottom: 0.25em;
+ line-height: 1.25em;
+ font-size: 2.5em;
+ color: #333;
+ font-weight: 600;
+}
+
+.PageDoc {
+ margin-top: 1.5em;
+}
+
+.PageDoc .header .headertitle .title {
+ display: none;
+}
+
+#shortdesc {
+ margin: 0;
+ color: #666;
+ display: inline-block;
+ font-style: italic;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ padding: 0;
+}
+
+#titlearea {
+ margin: 0.25em auto 0 auto;
+ padding: 0;
+ position: relative;
+ clear: both;
+ line-height: 1em;
+}
+
+.legend {
+ font-size: small;
+ text-align: center;
+}
+
+.version {
+ font-size: small;
+ text-align: center;
+}
+
+div.qindex,div.navtab {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+.contents a:visited {
+ color: #344E00;
+}
+
+a.qindexHL {
+ background-color: #9CAFD4;
+ color: #FFF;
+ border: 1px double #869DCA;
+}
+
+code {
+ color: #444;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+}
+
+dl.el {
+ margin-left: -1cm;
+}
+
+.fragment {
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+}
+
+pre.fragment {
+ border: 1px solid #C4C4C4;
+ background-color: #F9F9F9;
+ padding: 0.5em;
+ overflow: auto;
+}
+
+div.ah {
+ background-color: #000;
+ font-weight: 700;
+ color: #FFF;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: thin solid #333;
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: 700;
+}
+
+a + h2.groupheader {
+ display: none;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+div.contents, #content {
+ max-width: 60em;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.groupheader + p {
+ font-style: italic;
+ color: #666;
+ margin: 0 0 1em 0;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: 700;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0;
+ padding: 2px 10px;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0;
+}
+
+table.memname {
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+ border-spacing: 0;
+}
+
+table.memname tbody tr:last-child {
+ display: none;
+}
+
+table.memname tbody tr:only-child {
+ display: table-cell;
+}
+
+table.memname tbody tr:nth-last-child(2)::after {
+ content: ")";
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding: 0;
+}
+
+div.center img {
+ border: 0;
+}
+
+address.footer {
+ text-align: right;
+}
+
+img.footer {
+ border: 0;
+ vertical-align: middle;
+}
+
+span.keyword {
+ color: #586E75;
+}
+
+span.keywordtype {
+ color: #546E00;
+}
+
+span.keywordflow {
+ color: #586E75;
+}
+
+span.comment {
+ color: #6C71C4;
+}
+
+span.preprocessor {
+ color: #D33682;
+}
+
+span.stringliteral {
+ color: #CB4B16;
+}
+
+span.charliteral {
+ color: #CB4B16;
+}
+
+td.tiny {
+ font-size: x-small;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: 700;
+}
+
+hr {
+ height: 0;
+ border: none;
+ border-top: 1px solid #DDD;
+ margin: 2em 0;
+}
+
+#footer {
+ bottom: 0;
+ clear: both;
+ font-size: x-small;
+ margin: 2em 0 0;
+ padding: 0 1em 1em 1em;
+ vertical-align: top;
+ color: #888;
+}
+
+td.ititle {
+ padding-bottom: 0.75em;
+}
+
+table.memberdecls {
+ border-spacing: 0.125em;
+ line-height: 1.3em;
+}
+
+.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,.memTemplItemLeft,.memTemplItemRight,.memTemplParams {
+ margin: 0;
+ padding: 0;
+}
+
+.mdescLeft,.mdescRight {
+ color: #555;
+}
+
+.memItemLeft,.memItemRight,.memTemplParams {
+ border: 0;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+}
+
+.memItemLeft,.memTemplItemLeft {
+ white-space: nowrap;
+ padding-left: 2em;
+}
+
+.memItemLeft a.el {
+ font-weight: bold;
+}
+
+.memTemplParams {
+ color: #464646;
+ white-space: nowrap;
+}
+
+td.memSeparator {
+ display: none;
+}
+
+td.mlabels-right {
+ vertical-align: top;
+ padding-top: 4px;
+ color: #B4C342;
+}
+
+.memtitle {
+ display: none;
+}
+
+.memtemplate {
+ color: #888;
+ font-style: italic;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+ font-size: small;
+}
+
+.memnav {
+ background-color: #EEE;
+ border: 1px solid #B4C342;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.memitem {
+ padding: 0.5em 0.5em 0.25em 0.5em;
+ margin: 1em 0 2em 0;
+}
+
+.memproto {
+ border-bottom: 1px solid #EEE;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+ font-size: 1.09em;
+ font-weight: 600;
+ line-height: 1.41em;
+ margin-bottom: 0.25em;
+ padding-bottom: 0.125em;
+}
+
+.memproto .paramname {
+ font-style: normal;
+ padding-right: 0.25em;
+}
+
+.memdoc {
+ padding: 0;
+}
+
+.memdoc > p:first-child, .memdoc .textblock > p:first-child {
+ font-style: italic;
+ color: #444;
+ margin-bottom: 0.75em;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ color: #666;
+ padding: 0 0.25em 0 0.25em;
+ white-space: nowrap;
+}
+
+.params .paramname {
+ color: #111;
+ white-space: nowrap;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+ font-style: italic;
+ padding-right: 0.5em;
+ vertical-align: top;
+}
+
+.fieldname {
+ color: #000;
+}
+
+.fieldtable {
+ margin-top: 1em;
+ border-collapse: collapse;
+}
+
+.fieldtable tbody tr:first-child {
+ display: none;
+}
+
+td.fieldname {
+ vertical-align: top;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+}
+
+td.fielddoc {
+ padding: 0.125em 0.5em 0 0.25em;
+ vertical-align: top;
+}
+
+.fieldtable tbody tr td {
+ border-top: 1px dashed #DDD;
+ border-bottom: 1px dashed #DDD;
+}
+
+td.fieldtype {
+ color: #666;
+ padding: 0 0.5em 0 0;
+ vertical-align: top;
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+}
+
+td.fielddoc p {
+ margin: 0;
+ padding: 0 0.5em 0 0;
+}
+
+p.reference {
+ font-size: x-small;
+ font-style: italic;
+}
+
+.ftvtree {
+ font-family: "DejaVu Sans", Verdana, Helvetica, Arial, sans-serif;
+ margin: 0;
+}
+
+.directory {
+ margin: 0.5em;
+}
+
+.directory h3 {
+ margin: 0;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+
+.directory > h3 {
+ margin-top: 0;
+}
+
+.directory p {
+ margin: 0;
+ white-space: nowrap;
+}
+
+.directory div {
+ display: none;
+ margin: 0;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+td.entry {
+ font-family: "DejaVu Sans", Verdana, Helvetica, Arial, sans-serif;
+ font-weight: 400;
+ padding-right: 1em;
+}
+
+.arrow {
+ color: #CCC;
+ user-select: none;
+ font-size: 80%;
+ display: inline-block;
+ width: 16px;
+ height: 22px;
+ vertical-align: top;
+}
+
+td.entry b {
+ font-family: "DejaVu Sans", Verdana, Helvetica, Arial, sans-serif;
+ font-weight: 400;
+ font-size: 130%;
+}
+
+.directory-alt {
+ font-size: 100%;
+ font-weight: bold;
+}
+
+.directory-alt h3 {
+ margin: 0;
+ margin-top: 1em;
+ font-size: 11pt;
+}
+
+.directory-alt > h3 {
+ margin-top: 0;
+}
+
+.directory-alt p {
+ margin: 0;
+ white-space: nowrap;
+}
+
+.directory-alt div {
+ display: none;
+ margin: 0;
+}
+
+.directory-alt img {
+ vertical-align: -30%;
+}
+
+div.dynheader {
+ margin-top: 8px;
+}
+
+address {
+ font-style: normal;
+ color: #444;
+}
+
+table.doxtable {
+ border-collapse: collapse;
+ margin: 0.5em;
+}
+
+table.doxtable td,table.doxtable th {
+ border: 1px solid #DDD;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #F3F3F3;
+ color: #000;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align: left;
+ font-weight: bold;
+}
+
+.tabsearch {
+ top: 0;
+ left: 10px;
+ height: 36px;
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+div.navpath {
+ color: #DDD;
+}
+
+.navpath ul {
+ overflow: hidden;
+ margin: 0;
+ padding: 0;
+}
+
+.navpath li {
+ float: left;
+ padding-left: 0;
+ margin-left: 0.5em;
+ padding-right: 1em;
+}
+
+.navpath a {
+ display: block;
+ text-decoration: none;
+ outline: none;
+}
+
+div.summary {
+ font-size: small;
+ font-family: "DejaVu Sans", Verdana, Helvetica, Arial, sans-serif;
+ margin: 0;
+ padding: 0.25em 0;
+ display: none;
+}
+
+div.summary a {
+ white-space: nowrap;
+}
+
+#metabox {
+ display: inline-block;
+ font-size: x-small;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ position: absolute;
+ right: 0;
+ bottom: 0.25em;
+ color: #666;
+ font-style: italic;
+}
+
+#meta {
+ border-style: hidden;
+ margin-right: 0.25em;
+}
+
+#meta tr, #meta th, #meta td {
+ background-color: transparent;
+ border: 0;
+ margin: 0;
+ font-weight: normal;
+}
+
+#meta th {
+ text-align: right;
+}
+
+#meta th::after {
+ content: ":";
+}
+
+div.line {
+ font-family: "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace, fixed;
+ line-height: 1.4em;
+ white-space: pre-wrap;
+}
+
+.glow {
+ background-color: #2AA198;
+ box-shadow: 0 0 10px #2AA198;
+}
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #546E00;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+.tabs, .tabs2, .navpath {
+ padding: 0.25em 0;
+ font-size: small;
+ font-family: Helvetica, Arial, "DejaVu Sans Condensed", Verdana, sans-serif;
+ margin: 0;
+}
+
+th {
+ text-align: left;
+ font-size: 110%;
+ font-weight: 500;
+}
+
+.mlabel {
+ padding: 0.125em;
+}
+
+#navrow1, #navrow2 {
+ /* Disable menu from Doxygen 1.8.15, it is faked in the template */
+ display: none;
+}
+
+.tablist {
+ margin: 0;
+ padding: 0;
+ display: table;
+}
+
+.tablist li {
+ display: table-cell;
+ line-height: 2em;
+ list-style: none;
+ border-bottom: 0;
+}
+
+.tablist a {
+ display: block;
+ padding: 0 1em 0 0;
+ text-decoration: none;
+ outline: none;
+}
+
+.tabs3 .tablist a {
+ padding: 0 10px;
+}
+
+.tablist li.current a {
+ color: #222;
+}
+
+span.icon {
+ display: none;
+}
diff --git a/subprojects/d2tk/pugl/examples/cube_view.h b/subprojects/d2tk/pugl/examples/cube_view.h
new file mode 100644
index 00000000..9fd23495
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/cube_view.h
@@ -0,0 +1,82 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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.
+*/
+
+#define GL_SILENCE_DEPRECATION 1
+
+#include "demo_utils.h"
+
+#include "pugl/gl.h"
+
+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);
+}
diff --git a/subprojects/d2tk/pugl/examples/demo_utils.h b/subprojects/d2tk/pugl/examples/demo_utils.h
new file mode 100644
index 00000000..9a1cb7a1
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/demo_utils.h
@@ -0,0 +1,175 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 PUGL_DEMO_UTILS_H
+#define PUGL_DEMO_UTILS_H
+
+#include "pugl/pugl.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+ double lastReportTime;
+} PuglFpsPrinter;
+
+typedef float vec4[4];
+typedef vec4 mat4[4];
+
+// 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
+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,
+ "%u frames in %.0f seconds = %.3f FPS\n",
+ *framesDrawn,
+ thisTime - printer->lastReportTime,
+ fps);
+
+ printer->lastReportTime = thisTime;
+ *framesDrawn = 0;
+ }
+}
+
+#endif // PUGL_DEMO_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 00000000..38f442c8
--- /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 00000000..d8068c6d
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/glad/glad.h
@@ -0,0 +1,2129 @@
+/*
+
+ 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;
+struct _cl_context;
+struct _cl_event;
+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 00000000..5b55ea2b
--- /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/pugl_cairo_demo.c b/subprojects/d2tk/pugl/examples/pugl_cairo_demo.c
new file mode 100644
index 00000000..483446fb
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_cairo_demo.c
@@ -0,0 +1,270 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 pugl_cairo_demo.c An example of drawing with Cairo.
+*/
+
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/pugl.h"
+#include "pugl/pugl_cairo.h"
+
+#include <cairo.h>
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+ PuglTestOptions opts;
+ PuglWorld* world;
+ 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");
+
+ PuglRect frame = { 0, 0, 512, 512 };
+ PuglView* view = puglNewView(app.world);
+
+ puglSetWindowTitle(view, "Pugl Cairo Demo");
+ puglSetFrame(view, frame);
+ puglSetMinSize(view, 256, 256);
+ 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));
+ }
+
+ puglShowWindow(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_embed_demo.c b/subprojects/d2tk/pugl/examples/pugl_embed_demo.c
new file mode 100644
index 00000000..3a7b051e
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_embed_demo.c
@@ -0,0 +1,366 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 pugl_embed_demo.c An example of embedding a view in another.
+*/
+
+#include "cube_view.h"
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_gl.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;
+ bool continuous;
+ int quit;
+ double xAngle;
+ double yAngle;
+ float dist;
+ double lastMouseX;
+ double lastMouseY;
+ double lastDrawTime;
+ bool mouseEntered;
+ bool verbose;
+ bool reversing;
+} PuglTestApp;
+
+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
+};
+
+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 };
+ puglSetFrame(app.parent, parentFrame);
+ puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3);
+ 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));
+ }
+
+ puglShowWindow(app.parent);
+ puglShowWindow(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_gl3_demo.c b/subprojects/d2tk/pugl/examples/pugl_gl3_demo.c
new file mode 100644
index 00000000..c49ed3d6
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_gl3_demo.c
@@ -0,0 +1,432 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 pugl_gl3_demo.c An example of drawing with OpenGL 3.
+
+ 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 "shader_utils.h"
+#include "test/test_utils.h"
+
+#include "glad/glad.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_gl.h"
+
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const int defaultWidth = 512;
+static const int defaultHeight = 512;
+
+typedef struct
+{
+ float pos[2];
+ float size[2];
+ float fillColor[4];
+} Rect;
+
+// clang-format off
+static const GLfloat rectVertices[] = {
+ 0.0f, 0.0f, // TL
+ 1.0f, 0.0f, // TR
+ 0.0f, 1.0f, // BL
+ 1.0f, 1.0f, // BR
+};
+// clang-format on
+
+static const GLuint rectIndices[4] = {0, 1, 2, 3};
+
+typedef struct
+{
+ PuglTestOptions opts;
+ PuglWorld* world;
+ PuglView* view;
+ size_t numRects;
+ Rect* rects;
+ Program drawRect;
+ GLuint vao;
+ GLuint vbo;
+ GLuint instanceVbo;
+ GLuint ibo;
+ GLint u_projection;
+ unsigned framesDrawn;
+ 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);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ 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);
+
+ // Set projection matrix uniform
+ glUniformMatrix4fv(app->u_projection, 1, GL_FALSE, (const GLfloat*)&proj);
+
+ for (size_t i = 0; i < app->numRects; ++i) {
+ Rect* rect = &app->rects[i];
+ const float normal = i / (float)app->numRects;
+ const float offset[2] = {normal * 128.0f, normal * 128.0f};
+
+ // Move rect around in an arbitrary way that looks cool
+ rect->pos[0] = (width - rect->size[0] + offset[0]) *
+ (sinf((float)time * rect->size[0] / 64.0f + normal) +
+ 1.0f) /
+ 2.0f;
+ rect->pos[1] = (height - rect->size[1] + offset[1]) *
+ (cosf((float)time * rect->size[1] / 64.0f + normal) +
+ 1.0f) /
+ 2.0f;
+ }
+
+ 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;
+}
+
+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_KEY_PRESS:
+ if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
+ app->quit = 1;
+ }
+ break;
+ default: break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static Rect*
+makeRects(const size_t numRects)
+{
+ const float minSize = (float)defaultWidth / 64.0f;
+ const float maxSize = (float)defaultWidth / 6.0f;
+ const float boxAlpha = 0.2f;
+
+ Rect* rects = (Rect*)calloc(numRects, sizeof(Rect));
+ for (size_t i = 0; i < numRects; ++i) {
+ const float s = (sinf((float)i) / 2.0f + 0.5f);
+ const float c = (cosf((float)i) / 2.0f + 0.5f);
+
+ rects[i].size[0] = minSize + s * maxSize;
+ rects[i].size[1] = minSize + c * maxSize;
+ rects[i].fillColor[1] = s / 2.0f + 0.25f;
+ rects[i].fillColor[2] = c / 2.0f + 0.25f;
+ rects[i].fillColor[3] = boxAlpha;
+ }
+
+ return rects;
+}
+
+static char*
+loadShader(const char* const path)
+{
+ FILE* const file = fopen(path, "r");
+ if (!file) {
+ logError("Failed to open '%s'\n", path);
+ return NULL;
+ }
+
+ 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)
+{
+ // 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) {
+ char* endptr = NULL;
+
+ app->numRects = (size_t)strtol(argv[0], &endptr, 10);
+ if (endptr != argv[0] + strlen(argv[0])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+setupPugl(PuglTestApp* app, const PuglRect frame)
+{
+ // 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");
+ puglSetFrame(app->view, frame);
+ puglSetMinSize(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, 3);
+ puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MINOR, 3);
+ 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;
+ }
+
+ // Load shader sources
+ char* const vertexSource = loadShader("shaders/rect.vert");
+ char* const fragmentSource = loadShader("shaders/rect.frag");
+ if (!vertexSource || !fragmentSource) {
+ logError("Failed to load shader sources\n");
+ return PUGL_FAILURE;
+ }
+
+ // Compile rectangle shaders and program
+ app->drawRect = compileProgram(vertexSource, fragmentSource);
+ free(fragmentSource);
+ free(vertexSource);
+ if (!app->drawRect.program) {
+ return PUGL_FAILURE;
+ }
+
+ // Get location of rectangle shader uniforms
+ app->u_projection =
+ glGetUniformLocation(app->drawRect.program, "u_projection");
+
+ // 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;
+ memset(&app, 0, sizeof(app));
+
+ const PuglRect frame = {0, 0, defaultWidth, defaultHeight};
+
+ // Parse command line options
+ if (parseOptions(&app, argc, argv)) {
+ puglPrintTestUsage("pugl_gl3_demo", "[NUM_RECTS]");
+ return 1;
+ }
+
+ // Create and configure world and view
+ setupPugl(&app, frame);
+
+ // 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
+ puglShowWindow(app.view);
+
+ // Grind away, drawing continuously
+ PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
+ while (!app.quit) {
+ puglUpdate(app.world, 0.0);
+ 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_print_events.c b/subprojects/d2tk/pugl/examples/pugl_print_events.c
new file mode 100644
index 00000000..52b58c4b
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_print_events.c
@@ -0,0 +1,79 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 pugl_print_events.c A utility program that prints view events.
+*/
+
+#include "test/test_utils.h"
+
+#include "pugl/pugl.h"
+#include "pugl/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");
+ puglSetBackend(app.view, puglStubBackend());
+ puglSetHandle(app.view, &app);
+ puglSetEventFunc(app.view, onEvent);
+
+ if (puglRealize(app.view)) {
+ return logError("Failed to create window\n");
+ }
+
+ puglShowWindow(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_window_demo.c b/subprojects/d2tk/pugl/examples/pugl_window_demo.c
new file mode 100644
index 00000000..183119c6
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/pugl_window_demo.c
@@ -0,0 +1,252 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 pugl_window_demo.c A demonstration of multiple Pugl windows.
+*/
+
+#include "cube_view.h"
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/pugl.h"
+#include "pugl/pugl_gl.h"
+
+#include <math.h>
+#include <stdbool.h>
+#include <string.h>
+
+typedef struct {
+ PuglView* view;
+ double xAngle;
+ double yAngle;
+ float dist;
+ double lastMouseX;
+ double lastMouseY;
+ double lastDrawTime;
+ bool entered;
+} CubeView;
+
+typedef struct {
+ PuglWorld* world;
+ CubeView cubes[2];
+ bool continuous;
+ int quit;
+ bool verbose;
+} PuglTestApp;
+
+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 (size_t i = 0; i < 2; ++i) {
+ CubeView* cube = &app.cubes[i];
+ PuglView* view = cube->view;
+ static const double pad = 64.0;
+ const PuglRect frame = {pad + (256.0 + pad) * i,
+ pad + (256.0 + pad) * i,
+ 256.0,
+ 256.0};
+
+ cube->dist = 10;
+
+ puglSetWindowTitle(view, "Pugl Window Demo");
+ puglSetFrame(view, frame);
+ puglSetMinSize(view, 128, 128);
+ 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 ((st = puglRealize(view))) {
+ return logError("Failed to create window (%s)\n", puglStrerror(st));
+ }
+
+ puglShowWindow(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/shader_utils.h b/subprojects/d2tk/pugl/examples/shader_utils.h
new file mode 100644
index 00000000..834d8fcf
--- /dev/null
+++ b/subprojects/d2tk/pugl/examples/shader_utils.h
@@ -0,0 +1,97 @@
+/*
+ Copyright 2019 David Robillard <http://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 "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* source, const GLenum type)
+{
+ GLuint shader = glCreateShader(type);
+ const int sourceLength = (int)strlen(source);
+ glShaderSource(shader, 1, &source, &sourceLength);
+ glCompileShader(shader);
+
+ int status;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (status == GL_FALSE) {
+ GLint length;
+ 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* vertexSource, const char* fragmentSource)
+{
+ static const Program nullProgram = {0, 0, 0};
+
+ Program program = {compileShader(vertexSource, GL_VERTEX_SHADER),
+ compileShader(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;
+ glGetProgramiv(program.program, GL_LINK_STATUS, &status);
+ if (status == GL_FALSE) {
+ GLint length;
+ 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;
+}
diff --git a/subprojects/d2tk/pugl/pugl.pc.in b/subprojects/d2tk/pugl/pugl.pc.in
index d3606cdd..531cd54a 100644
--- a/subprojects/d2tk/pugl/pugl.pc.in
+++ b/subprojects/d2tk/pugl/pugl.pc.in
@@ -3,8 +3,9 @@ exec_prefix=@EXEC_PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
-Name: Pugl
+Name: @NAME@
+Description: @DESCRIPTION@
Version: @PUGL_VERSION@
-Description: Lightweight portable OpenGL API
-Libs: -L${libdir} -l@LIB_PUGL@
+Requires: @REQUIRES@
+Libs: -L${libdir} @LIBS@
Cflags: -I${includedir}/pugl-@PUGL_MAJOR_VERSION@
diff --git a/subprojects/d2tk/pugl/pugl/cairo_gl.h b/subprojects/d2tk/pugl/pugl/cairo_gl.h
deleted file mode 100644
index fb4cb2a4..00000000
--- a/subprojects/d2tk/pugl/pugl/cairo_gl.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- Copyright 2016 David Robillard <http://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(PUGL_HAVE_GL) && defined(PUGL_HAVE_CAIRO)
-
-#include <cairo/cairo.h>
-#include <stdint.h>
-
-#include "pugl/gl.h"
-
-typedef struct {
- unsigned texture_id;
- uint8_t* buffer;
-} PuglCairoGL;
-
-static cairo_surface_t*
-pugl_cairo_gl_create(PuglCairoGL* ctx, int width, int height, int bpp)
-{
- free(ctx->buffer);
- ctx->buffer = (uint8_t*)calloc(bpp * width * height, sizeof(uint8_t));
- if (!ctx->buffer) {
- fprintf(stderr, "failed to allocate surface buffer\n");
- return NULL;
- }
-
- return cairo_image_surface_create_for_data(
- ctx->buffer, CAIRO_FORMAT_ARGB32, width, height, bpp * width);
-}
-
-static void
-pugl_cairo_gl_free(PuglCairoGL* ctx)
-{
- free(ctx->buffer);
- ctx->buffer = NULL;
-}
-
-static void
-pugl_cairo_gl_configure(PuglCairoGL* ctx,
- int width __attribute__((unused)), int height __attribute__((unused)))
-{
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_TEXTURE_RECTANGLE_ARB);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- glDeleteTextures(1, &ctx->texture_id);
- glGenTextures(1, &ctx->texture_id);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ctx->texture_id);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-}
-
-static void
-pugl_cairo_gl_draw(PuglCairoGL* ctx, int width, int height)
-{
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glViewport(0, 0, width, height);
- glClear(GL_COLOR_BUFFER_BIT);
-
- glPushMatrix();
- glEnable(GL_TEXTURE_RECTANGLE_ARB);
- glEnable(GL_TEXTURE_2D);
-
- glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
- width, height, 0,
- GL_BGRA, GL_UNSIGNED_BYTE, ctx->buffer);
-
- glBegin(GL_QUADS);
- glTexCoord2f(0.0f, (GLfloat)height);
- glVertex2f(-1.0f, -1.0f);
-
- glTexCoord2f((GLfloat)width, (GLfloat)height);
- glVertex2f(1.0f, -1.0f);
-
- glTexCoord2f((GLfloat)width, 0.0f);
- glVertex2f(1.0f, 1.0f);
-
- glTexCoord2f(0.0f, 0.0f);
- glVertex2f(-1.0f, 1.0f);
- glEnd();
-
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_TEXTURE_RECTANGLE_ARB);
- glPopMatrix();
-}
-
-#endif
diff --git a/subprojects/d2tk/pugl/pugl/detail/implementation.c b/subprojects/d2tk/pugl/pugl/detail/implementation.c
new file mode 100644
index 00000000..ee9b242c
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/implementation.c
@@ -0,0 +1,467 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 implementation.c Platform-independent implementation.
+*/
+
+#include "pugl/detail/implementation.h"
+#include "pugl/pugl.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char*
+puglLogLevelPrefix(const PuglLogLevel level)
+{
+ switch (level) {
+ case PUGL_LOG_LEVEL_ERR:
+ return "error: ";
+ case PUGL_LOG_LEVEL_WARNING:
+ return "warning: ";
+ case PUGL_LOG_LEVEL_INFO:
+ case PUGL_LOG_LEVEL_DEBUG:
+ return "";
+ }
+
+ return "";
+}
+
+static void
+puglDefaultLogFunc(PuglWorld* PUGL_UNUSED(world),
+ PuglLogLevel level,
+ const char* msg)
+{
+ fprintf(stderr, "%s%s", puglLogLevelPrefix(level), msg);
+}
+
+const char*
+puglStrerror(const PuglStatus status)
+{
+ // clang-format off
+ switch (status) {
+ case PUGL_SUCCESS: return "Success";
+ case PUGL_FAILURE: return "Non-fatal failure";
+ case PUGL_UNKNOWN_ERROR: return "Unknown system error";
+ case PUGL_BAD_BACKEND: return "Invalid or missing backend";
+ case PUGL_BAD_PARAMETER: return "Invalid parameter";
+ case PUGL_BACKEND_FAILED: return "Backend initialisation failed";
+ case PUGL_REGISTRATION_FAILED: return "Class registration failed";
+ case PUGL_REALIZE_FAILED: return "View creation failed";
+ case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format";
+ case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context";
+ case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type";
+ }
+ // clang-format on
+
+ return "Unknown error";
+}
+
+void
+puglSetString(char** dest, const char* string)
+{
+ if (*dest != string) {
+ const size_t len = strlen(string);
+
+ *dest = (char*)realloc(*dest, len + 1);
+ strncpy(*dest, string, len + 1);
+ }
+}
+
+void
+puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len)
+{
+ if (data) {
+ dest->len = len;
+ dest->data = realloc(dest->data, len + 1);
+ memcpy(dest->data, data, len);
+ ((char*)dest->data)[len] = 0;
+ } else {
+ dest->len = 0;
+ dest->data = NULL;
+ }
+}
+
+static void
+puglSetDefaultHints(PuglHints hints)
+{
+ hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE;
+ hints[PUGL_CONTEXT_VERSION_MAJOR] = 2;
+ hints[PUGL_CONTEXT_VERSION_MINOR] = 0;
+ hints[PUGL_RED_BITS] = 4;
+ hints[PUGL_GREEN_BITS] = 4;
+ hints[PUGL_BLUE_BITS] = 4;
+ hints[PUGL_ALPHA_BITS] = 4;
+ hints[PUGL_DEPTH_BITS] = 24;
+ hints[PUGL_STENCIL_BITS] = 8;
+ hints[PUGL_SAMPLES] = 0;
+ hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE;
+ hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE;
+ hints[PUGL_RESIZABLE] = PUGL_FALSE;
+ hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE;
+}
+
+PuglWorld*
+puglNewWorld(PuglWorldType type, PuglWorldFlags flags)
+{
+ PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld));
+ if (!world || !(world->impl = puglInitWorldInternals(type, flags))) {
+ free(world);
+ return NULL;
+ }
+
+ world->startTime = puglGetTime(world);
+ world->logFunc = puglDefaultLogFunc;
+ world->logLevel = PUGL_LOG_LEVEL_INFO;
+
+ puglSetString(&world->className, "Pugl");
+
+ return world;
+}
+
+void
+puglFreeWorld(PuglWorld* const world)
+{
+ puglFreeWorldInternals(world);
+ free(world->className);
+ free(world->views);
+ free(world);
+}
+
+void
+puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle)
+{
+ world->handle = handle;
+}
+
+PuglWorldHandle
+puglGetWorldHandle(PuglWorld* world)
+{
+ return world->handle;
+}
+
+PuglStatus
+puglSetLogFunc(PuglWorld* world, PuglLogFunc logFunc)
+{
+ world->logFunc = logFunc;
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetLogLevel(PuglWorld* world, PuglLogLevel level)
+{
+ world->logLevel = level;
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetClassName(PuglWorld* const world, const char* const name)
+{
+ puglSetString(&world->className, name);
+ return PUGL_SUCCESS;
+}
+
+PuglView*
+puglNewView(PuglWorld* const world)
+{
+ PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
+ if (!view || !(view->impl = puglInitViewInternals())) {
+ free(view);
+ return NULL;
+ }
+
+ view->world = world;
+ view->frame.width = 640;
+ view->frame.height = 480;
+
+ puglSetDefaultHints(view->hints);
+
+ // Add to world view list
+ ++world->numViews;
+ world->views = (PuglView**)realloc(world->views,
+ world->numViews * sizeof(PuglView*));
+
+ world->views[world->numViews - 1] = view;
+
+ return view;
+}
+
+void
+puglFreeView(PuglView* view)
+{
+ puglDispatchSimpleEvent(view, PUGL_DESTROY);
+
+ // Remove from world view list
+ PuglWorld* world = view->world;
+ for (size_t i = 0; i < world->numViews; ++i) {
+ if (world->views[i] == view) {
+ if (i == world->numViews - 1) {
+ world->views[i] = NULL;
+ } else {
+ memmove(world->views + i, world->views + i + 1,
+ sizeof(PuglView*) * (world->numViews - i - 1));
+ world->views[world->numViews - 1] = NULL;
+ }
+ --world->numViews;
+ }
+ }
+
+ free(view->title);
+ free(view->clipboard.data);
+ puglFreeViewInternals(view);
+ free(view);
+}
+
+PuglWorld*
+puglGetWorld(PuglView* view)
+{
+ return view->world;
+}
+
+PuglStatus
+puglSetViewHint(PuglView* view, PuglViewHint hint, int value)
+{
+ if (hint < PUGL_NUM_VIEW_HINTS) {
+ view->hints[hint] = value;
+ return PUGL_SUCCESS;
+ }
+
+ return PUGL_BAD_PARAMETER;
+}
+
+PuglStatus
+puglSetParentWindow(PuglView* view, PuglNativeView parent)
+{
+ view->parent = parent;
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetBackend(PuglView* view, const PuglBackend* backend)
+{
+ view->backend = backend;
+ return PUGL_SUCCESS;
+}
+
+void
+puglSetHandle(PuglView* view, PuglHandle handle)
+{
+ view->handle = handle;
+}
+
+PuglHandle
+puglGetHandle(PuglView* view)
+{
+ return view->handle;
+}
+
+bool
+puglGetVisible(const PuglView* view)
+{
+ return view->visible;
+}
+
+PuglRect
+puglGetFrame(const PuglView* view)
+{
+ return view->frame;
+}
+
+void*
+puglGetContext(PuglView* view)
+{
+ return view->backend->getContext(view);
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+
+PuglStatus
+puglPollEvents(PuglWorld* world, double timeout)
+{
+ return puglUpdate(world, timeout);
+}
+
+PuglStatus
+puglDispatchEvents(PuglWorld* world)
+{
+ return puglUpdate(world, 0.0);
+}
+
+PuglStatus
+puglEnterContext(PuglView* view, bool drawing)
+{
+ const PuglEventExpose expose = {
+ PUGL_EXPOSE, 0, 0, 0, view->frame.width, view->frame.height, 0};
+
+ view->backend->enter(view, drawing ? &expose : NULL);
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglLeaveContext(PuglView* view, bool drawing)
+{
+ const PuglEventExpose expose = {
+ PUGL_EXPOSE, 0, 0, 0, view->frame.width, view->frame.height, 0};
+
+ view->backend->leave(view, drawing ? &expose : NULL);
+
+ return PUGL_SUCCESS;
+}
+
+#endif
+
+PuglStatus
+puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc)
+{
+ view->eventFunc = eventFunc;
+ return PUGL_SUCCESS;
+}
+
+/** Return the code point for buf, or the replacement character on error. */
+uint32_t
+puglDecodeUTF8(const uint8_t* buf)
+{
+#define FAIL_IF(cond) do { if (cond) return 0xFFFD; } while (0)
+
+ // http://en.wikipedia.org/wiki/UTF-8
+
+ if (buf[0] < 0x80) {
+ return buf[0];
+ } else if (buf[0] < 0xC2) {
+ return 0xFFFD;
+ } else if (buf[0] < 0xE0) {
+ FAIL_IF((buf[1] & 0xC0u) != 0x80);
+ return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u;
+ } else if (buf[0] < 0xF0) {
+ FAIL_IF((buf[1] & 0xC0u) != 0x80);
+ FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0);
+ FAIL_IF((buf[2] & 0xC0u) != 0x80);
+ return ((uint32_t)buf[0] << 12u) + //
+ ((uint32_t)buf[1] << 6u) + //
+ ((uint32_t)buf[2] - 0xE2080u);
+ } else if (buf[0] < 0xF5) {
+ FAIL_IF((buf[1] & 0xC0u) != 0x80);
+ FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90);
+ FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90);
+ FAIL_IF((buf[2] & 0xC0u) != 0x80u);
+ FAIL_IF((buf[3] & 0xC0u) != 0x80u);
+ return (((uint32_t)buf[0] << 18u) + //
+ ((uint32_t)buf[1] << 12u) + //
+ ((uint32_t)buf[2] << 6u) + //
+ ((uint32_t)buf[3] - 0x3C82080u));
+ }
+ return 0xFFFD;
+}
+
+static inline bool
+puglMustConfigure(PuglView* view, const PuglEventConfigure* configure)
+{
+ return memcmp(configure, &view->lastConfigure, sizeof(PuglEventConfigure));
+}
+
+void
+puglDispatchSimpleEvent(PuglView* view, const PuglEventType type)
+{
+ assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP ||
+ type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE);
+
+ const PuglEvent event = {{type, 0}};
+ puglDispatchEvent(view, &event);
+}
+
+void
+puglDispatchEventInContext(PuglView* view, const PuglEvent* event)
+{
+ if (event->type == PUGL_CONFIGURE) {
+ view->frame.x = event->configure.x;
+ view->frame.y = event->configure.y;
+ view->frame.width = event->configure.width;
+ view->frame.height = event->configure.height;
+
+ if (puglMustConfigure(view, &event->configure)) {
+ view->eventFunc(view, event);
+ view->lastConfigure = event->configure;
+ }
+ } else {
+ view->eventFunc(view, event);
+ }
+}
+
+void
+puglDispatchEvent(PuglView* view, const PuglEvent* event)
+{
+ switch (event->type) {
+ case PUGL_NOTHING:
+ break;
+ case PUGL_CREATE:
+ case PUGL_DESTROY:
+ view->backend->enter(view, NULL);
+ view->eventFunc(view, event);
+ view->backend->leave(view, NULL);
+ break;
+ case PUGL_CONFIGURE:
+ if (puglMustConfigure(view, &event->configure)) {
+ view->backend->enter(view, NULL);
+ puglDispatchEventInContext(view, event);
+ view->backend->leave(view, NULL);
+ }
+ break;
+ case PUGL_EXPOSE:
+ view->backend->enter(view, &event->expose);
+ view->eventFunc(view, event);
+ view->backend->leave(view, &event->expose);
+ break;
+ default:
+ view->eventFunc(view, event);
+ }
+}
+
+const void*
+puglGetInternalClipboard(const PuglView* const view,
+ const char** const type,
+ size_t* const len)
+{
+ if (len) {
+ *len = view->clipboard.len;
+ }
+
+ if (type) {
+ *type = "text/plain";
+ }
+
+ return view->clipboard.data;
+}
+
+PuglStatus
+puglSetInternalClipboard(PuglView* const view,
+ const char* const type,
+ const void* const data,
+ const size_t len)
+{
+ if (type && strcmp(type, "text/plain")) {
+ return PUGL_UNSUPPORTED_TYPE;
+ }
+
+ puglSetBlob(&view->clipboard, data, len);
+ return PUGL_SUCCESS;
+}
+
diff --git a/subprojects/d2tk/pugl/pugl/detail/implementation.h b/subprojects/d2tk/pugl/pugl/detail/implementation.h
new file mode 100644
index 00000000..bcecd858
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/implementation.h
@@ -0,0 +1,76 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 implementation.h Shared declarations for implementation.
+*/
+
+#ifndef PUGL_DETAIL_IMPLEMENTATION_H
+#define PUGL_DETAIL_IMPLEMENTATION_H
+
+#include "pugl/detail/types.h"
+#include "pugl/pugl.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+PUGL_BEGIN_DECLS
+
+/** Set `blob` to `data` with length `len`, reallocating if necessary. */
+void puglSetBlob(PuglBlob* dest, const void* data, size_t len);
+
+/** Reallocate and set `*dest` to `string`. */
+void puglSetString(char** dest, const char* string);
+
+/** Allocate and initialise world internals (implemented once per platform) */
+PuglWorldInternals*
+puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags);
+
+/** Destroy and free world internals (implemented once per platform) */
+void puglFreeWorldInternals(PuglWorld* world);
+
+/** Allocate and initialise view internals (implemented once per platform) */
+PuglInternals* puglInitViewInternals(void);
+
+/** Destroy and free view internals (implemented once per platform) */
+void puglFreeViewInternals(PuglView* view);
+
+/** Return the Unicode code point for `buf` or the replacement character. */
+uint32_t puglDecodeUTF8(const uint8_t* buf);
+
+/** Dispatch an event with a simple `type` to `view`. */
+void puglDispatchSimpleEvent(PuglView* view, PuglEventType type);
+
+/** Dispatch `event` to `view` while already in the graphics context. */
+void puglDispatchEventInContext(PuglView* view, const PuglEvent* event);
+
+/** Dispatch `event` to `view`, entering graphics context if necessary. */
+void puglDispatchEvent(PuglView* view, const PuglEvent* event);
+
+/** Set internal (stored in view) clipboard contents. */
+const void*
+puglGetInternalClipboard(const PuglView* view, const char** type, size_t* len);
+
+/** Set internal (stored in view) clipboard contents. */
+PuglStatus
+puglSetInternalClipboard(PuglView* view,
+ const char* type,
+ const void* data,
+ size_t len);
+
+PUGL_END_DECLS
+
+#endif // PUGL_DETAIL_IMPLEMENTATION_H
diff --git a/subprojects/d2tk/pugl/pugl/detail/mac.h b/subprojects/d2tk/pugl/pugl/detail/mac.h
new file mode 100644
index 00000000..2243337a
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/mac.h
@@ -0,0 +1,65 @@
+/*
+ Copyright 2012-2019 David Robillard <http://drobilla.net>
+ Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch>
+
+ 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 mac.h Shared definitions for MacOS implementation.
+*/
+
+#include "pugl/pugl.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include <stdint.h>
+
+@interface PuglWrapperView : NSView<NSTextInputClient>
+{
+@public
+ PuglView* puglview;
+ NSTrackingArea* trackingArea;
+ NSMutableAttributedString* markedText;
+ NSTimer* timer;
+ NSMutableDictionary* userTimers;
+ bool reshaped;
+}
+
+- (void) dispatchExpose:(NSRect)rect;
+- (void) setReshaped;
+
+@end
+
+@interface PuglWindow : NSWindow
+{
+@public
+ PuglView* puglview;
+}
+
+- (void) setPuglview:(PuglView*)view;
+
+@end
+
+struct PuglWorldInternalsImpl {
+ NSApplication* app;
+ NSAutoreleasePool* autoreleasePool;
+};
+
+struct PuglInternalsImpl {
+ NSApplication* app;
+ PuglWrapperView* wrapperView;
+ NSView* drawView;
+ PuglWindow* window;
+ uint32_t mods;
+};
diff --git a/subprojects/d2tk/pugl/pugl/detail/mac.m b/subprojects/d2tk/pugl/pugl/detail/mac.m
new file mode 100644
index 00000000..501be02d
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/mac.m
@@ -0,0 +1,1200 @@
+/*
+ Copyright 2012-2020 David Robillard <http://drobilla.net>
+ Copyright 2017 Hanspeter Portner <dev@open-music-kontrollers.ch>
+
+ 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 mac.m MacOS implementation.
+*/
+
+#define GL_SILENCE_DEPRECATION 1
+
+#include "pugl/detail/implementation.h"
+#include "pugl/detail/mac.h"
+#include "pugl/pugl.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include <mach/mach_time.h>
+
+#include <stdlib.h>
+
+#ifndef __MAC_10_10
+typedef NSUInteger NSEventModifierFlags;
+#endif
+
+#ifndef __MAC_10_12
+typedef NSUInteger NSWindowStyleMask;
+#endif
+
+static NSRect
+rectToScreen(NSRect rect)
+{
+ const double screenHeight = [[NSScreen mainScreen] frame].size.height;
+
+ rect.origin.y = screenHeight - rect.origin.y - rect.size.height;
+ return rect;
+}
+
+static void
+updateViewRect(PuglView* view)
+{
+ NSWindow* const window = view->impl->window;
+ if (window) {
+ const double screenHeight = [[NSScreen mainScreen] frame].size.height;
+ const NSRect frame = [window frame];
+ const NSRect content = [window contentRectForFrameRect:frame];
+
+ view->frame.x = content.origin.x;
+ view->frame.y = screenHeight - content.origin.y - content.size.height;
+ view->frame.width = content.size.width;
+ view->frame.height = content.size.height;
+ }
+}
+
+@implementation PuglWindow
+
+- (id) initWithContentRect:(NSRect)contentRect
+ styleMask:(NSWindowStyleMask)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag
+{
+ (void)flag;
+
+ NSWindow* result = [super initWithContentRect:contentRect
+ styleMask:aStyle
+ backing:bufferingType
+ defer:NO];
+
+ [result setAcceptsMouseMovedEvents:YES];
+ return (PuglWindow*)result;
+}
+
+- (void)setPuglview:(PuglView*)view
+{
+ puglview = view;
+ [self setContentSize:NSMakeSize(view->frame.width, view->frame.height)];
+}
+
+- (BOOL) canBecomeKeyWindow
+{
+ return YES;
+}
+
+- (BOOL) canBecomeMainWindow
+{
+ return YES;
+}
+
+- (void) setIsVisible:(BOOL)flag
+{
+ if (flag && !puglview->visible) {
+ const PuglEventConfigure ev = {
+ PUGL_CONFIGURE,
+ 0,
+ puglview->frame.x,
+ puglview->frame.y,
+ puglview->frame.width,
+ puglview->frame.height,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+ puglDispatchSimpleEvent(puglview, PUGL_MAP);
+ } else if (!flag && puglview->visible) {
+ puglDispatchSimpleEvent(puglview, PUGL_UNMAP);
+ }
+
+ puglview->visible = flag;
+
+ [super setIsVisible:flag];
+}
+
+@end
+
+@implementation PuglWrapperView
+
+- (void) dispatchExpose:(NSRect)rect
+{
+ if (reshaped) {
+ updateViewRect(puglview);
+
+ const PuglEventConfigure ev = {
+ PUGL_CONFIGURE,
+ 0,
+ puglview->frame.x,
+ puglview->frame.y,
+ puglview->frame.width,
+ puglview->frame.height,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+ reshaped = false;
+ }
+
+ if (![[puglview->impl->drawView window] isVisible]) {
+ return;
+ }
+
+ const PuglEventExpose ev = {
+ PUGL_EXPOSE,
+ 0,
+ rect.origin.x,
+ rect.origin.y,
+ rect.size.width,
+ rect.size.height,
+ 0
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (BOOL) isFlipped
+{
+ return YES;
+}
+
+- (BOOL) acceptsFirstResponder
+{
+ return YES;
+}
+
+- (void) setReshaped
+{
+ reshaped = true;
+}
+
+static uint32_t
+getModifiers(const NSEvent* const ev)
+{
+ const NSEventModifierFlags modifierFlags = [ev modifierFlags];
+
+ return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) |
+ ((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) |
+ ((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) |
+ ((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0));
+}
+
+static PuglKey
+keySymToSpecial(const NSEvent* const ev)
+{
+ NSString* chars = [ev charactersIgnoringModifiers];
+ if ([chars length] == 1) {
+ switch ([chars characterAtIndex:0]) {
+ case NSF1FunctionKey: return PUGL_KEY_F1;
+ case NSF2FunctionKey: return PUGL_KEY_F2;
+ case NSF3FunctionKey: return PUGL_KEY_F3;
+ case NSF4FunctionKey: return PUGL_KEY_F4;
+ case NSF5FunctionKey: return PUGL_KEY_F5;
+ case NSF6FunctionKey: return PUGL_KEY_F6;
+ case NSF7FunctionKey: return PUGL_KEY_F7;
+ case NSF8FunctionKey: return PUGL_KEY_F8;
+ case NSF9FunctionKey: return PUGL_KEY_F9;
+ case NSF10FunctionKey: return PUGL_KEY_F10;
+ case NSF11FunctionKey: return PUGL_KEY_F11;
+ case NSF12FunctionKey: return PUGL_KEY_F12;
+ case NSDeleteCharacter: return PUGL_KEY_BACKSPACE;
+ case NSDeleteFunctionKey: return PUGL_KEY_DELETE;
+ case NSLeftArrowFunctionKey: return PUGL_KEY_LEFT;
+ case NSUpArrowFunctionKey: return PUGL_KEY_UP;
+ case NSRightArrowFunctionKey: return PUGL_KEY_RIGHT;
+ case NSDownArrowFunctionKey: return PUGL_KEY_DOWN;
+ case NSPageUpFunctionKey: return PUGL_KEY_PAGE_UP;
+ case NSPageDownFunctionKey: return PUGL_KEY_PAGE_DOWN;
+ case NSHomeFunctionKey: return PUGL_KEY_HOME;
+ case NSEndFunctionKey: return PUGL_KEY_END;
+ case NSInsertFunctionKey: return PUGL_KEY_INSERT;
+ case NSMenuFunctionKey: return PUGL_KEY_MENU;
+ case NSScrollLockFunctionKey: return PUGL_KEY_SCROLL_LOCK;
+ case NSClearLineFunctionKey: return PUGL_KEY_NUM_LOCK;
+ case NSPrintScreenFunctionKey: return PUGL_KEY_PRINT_SCREEN;
+ case NSPauseFunctionKey: return PUGL_KEY_PAUSE;
+ }
+ // SHIFT, CTRL, ALT, and SUPER are handled in [flagsChanged]
+ }
+ return (PuglKey)0;
+}
+
+- (void) updateTrackingAreas
+{
+ if (trackingArea != nil) {
+ [self removeTrackingArea:trackingArea];
+ [trackingArea release];
+ }
+
+ const int opts = (NSTrackingMouseEnteredAndExited |
+ NSTrackingMouseMoved |
+ NSTrackingActiveAlways);
+ trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
+ options:opts
+ owner:self
+ userInfo:nil];
+ [self addTrackingArea:trackingArea];
+ [super updateTrackingAreas];
+}
+
+- (NSPoint) eventLocation:(NSEvent*)event
+{
+ return [self convertPoint:[event locationInWindow] fromView:nil];
+}
+
+static void
+handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
+{
+ const NSPoint wloc = [view eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglEventCrossing ev = {
+ type,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ PUGL_CROSSING_NORMAL,
+ };
+
+ puglDispatchEvent(view->puglview, (const PuglEvent*)&ev);
+}
+
+- (void) mouseEntered:(NSEvent*)event
+{
+ handleCrossing(self, event, PUGL_POINTER_IN);
+}
+
+- (void) mouseExited:(NSEvent*)event
+{
+ handleCrossing(self, event, PUGL_POINTER_OUT);
+}
+
+- (void) mouseMoved:(NSEvent*)event
+{
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglEventMotion ev = {
+ PUGL_MOTION,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ 0,
+ 1,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (void) mouseDragged:(NSEvent*)event
+{
+ [self mouseMoved: event];
+}
+
+- (void) rightMouseDragged:(NSEvent*)event
+{
+ [self mouseMoved: event];
+}
+
+- (void) otherMouseDragged:(NSEvent*)event
+{
+ [self mouseMoved: event];
+}
+
+- (void) mouseDown:(NSEvent*)event
+{
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglEventButton ev = {
+ PUGL_BUTTON_PRESS,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ (uint32_t)[event buttonNumber] + 1,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (void) mouseUp:(NSEvent*)event
+{
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglEventButton ev = {
+ PUGL_BUTTON_RELEASE,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ (uint32_t)[event buttonNumber] + 1,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (void) rightMouseDown:(NSEvent*)event
+{
+ [self mouseDown: event];
+}
+
+- (void) rightMouseUp:(NSEvent*)event
+{
+ [self mouseUp: event];
+}
+
+- (void) otherMouseDown:(NSEvent*)event
+{
+ [self mouseDown: event];
+}
+
+- (void) otherMouseUp:(NSEvent*)event
+{
+ [self mouseUp: event];
+}
+
+- (void) scrollWheel:(NSEvent*)event
+{
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglEventScroll ev = {
+ PUGL_SCROLL,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ [event scrollingDeltaX],
+ [event scrollingDeltaY],
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (void) keyDown:(NSEvent*)event
+{
+ if (puglview->hints[PUGL_IGNORE_KEY_REPEAT] && [event isARepeat]) {
+ return;
+ }
+
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglKey spec = keySymToSpecial(event);
+ const NSString* chars = [event charactersIgnoringModifiers];
+ const char* str = [[chars lowercaseString] UTF8String];
+ const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str));
+
+ const PuglEventKey ev = {
+ PUGL_KEY_PRESS,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ [event keyCode],
+ (code != 0xFFFD) ? code : 0,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+
+ if (!spec) {
+ [self interpretKeyEvents:@[event]];
+ }
+}
+
+- (void)keyUp:(NSEvent*)event
+{
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ const PuglKey spec = keySymToSpecial(event);
+ const NSString* chars = [event charactersIgnoringModifiers];
+ const char* str = [[chars lowercaseString] UTF8String];
+ const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str));
+
+ const PuglEventKey ev = {
+ PUGL_KEY_RELEASE,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ [event keyCode],
+ (code != 0xFFFD) ? code : 0,
+ };
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (BOOL) hasMarkedText
+{
+ return [markedText length] > 0;
+}
+
+- (NSRange) markedRange
+{
+ return (([markedText length] > 0)
+ ? NSMakeRange(0, [markedText length] - 1)
+ : NSMakeRange(NSNotFound, 0));
+}
+
+- (NSRange) selectedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (void)setMarkedText:(id)string
+ selectedRange:(NSRange)selected
+ replacementRange:(NSRange)replacement
+{
+ (void)selected;
+ (void)replacement;
+ [markedText release];
+ markedText = (
+ [(NSObject*)string isKindOfClass:[NSAttributedString class]]
+ ? [[NSMutableAttributedString alloc] initWithAttributedString:string]
+ : [[NSMutableAttributedString alloc] initWithString:string]);
+}
+
+- (void) unmarkText
+{
+ [[markedText mutableString] setString:@""];
+}
+
+- (NSArray*) validAttributesForMarkedText
+{
+ return @[];
+}
+
+- (NSAttributedString*)
+ attributedSubstringForProposedRange:(NSRange)range
+ actualRange:(NSRangePointer)actual
+{
+ (void)range;
+ (void)actual;
+ return nil;
+}
+
+- (NSUInteger) characterIndexForPoint:(NSPoint)point
+{
+ (void)point;
+ return 0;
+}
+
+- (NSRect) firstRectForCharacterRange:(NSRange)range
+ actualRange:(NSRangePointer)actual
+{
+ (void)range;
+ (void)actual;
+
+ const NSRect frame = [self bounds];
+ return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0);
+}
+
+- (void) doCommandBySelector:(SEL)selector
+{
+ (void)selector;
+}
+
+- (void) insertText:(id)string
+ replacementRange:(NSRange)replacement
+{
+ (void)replacement;
+
+ NSEvent* const event = [NSApp currentEvent];
+ NSString* const characters =
+ ([(NSObject*)string isKindOfClass:[NSAttributedString class]]
+ ? [(NSAttributedString*)string string]
+ : (NSString*)string);
+
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ for (size_t i = 0; i < [characters length]; ++i) {
+ const uint32_t code = [characters characterAtIndex:i];
+ char utf8[8] = {0};
+ NSUInteger len = 0;
+
+ [characters getBytes:utf8
+ maxLength:sizeof(utf8)
+ usedLength:&len
+ encoding:NSUTF8StringEncoding
+ options:0
+ range:NSMakeRange(i, i + 1)
+ remainingRange:nil];
+
+ PuglEventText ev = {
+ PUGL_TEXT,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ getModifiers(event),
+ [event keyCode],
+ code,
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ };
+
+ memcpy(ev.string, utf8, len);
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+ }
+}
+
+- (void) flagsChanged:(NSEvent*)event
+{
+ const uint32_t mods = getModifiers(event);
+ PuglEventType type = PUGL_NOTHING;
+ PuglKey special = (PuglKey)0;
+
+ if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) {
+ type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
+ special = PUGL_KEY_SHIFT;
+ } else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) {
+ type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
+ special = PUGL_KEY_CTRL;
+ } else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) {
+ type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
+ special = PUGL_KEY_ALT;
+ } else if ((mods & PUGL_MOD_SUPER) != (puglview->impl->mods & PUGL_MOD_SUPER)) {
+ type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
+ special = PUGL_KEY_SUPER;
+ }
+
+ if (special != 0) {
+ const NSPoint wloc = [self eventLocation:event];
+ const NSPoint rloc = [NSEvent mouseLocation];
+ PuglEventKey ev = {
+ type,
+ 0,
+ [event timestamp],
+ wloc.x,
+ wloc.y,
+ rloc.x,
+ [[NSScreen mainScreen] frame].size.height - rloc.y,
+ mods,
+ [event keyCode],
+ special
+ };
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+ }
+
+ puglview->impl->mods = mods;
+}
+
+- (BOOL) preservesContentInLiveResize
+{
+ return NO;
+}
+
+- (void) viewWillStartLiveResize
+{
+ timer = [NSTimer timerWithTimeInterval:(1 / 60.0)
+ target:self
+ selector:@selector(resizeTick)
+ userInfo:nil
+ repeats:YES];
+ [[NSRunLoop currentRunLoop] addTimer:timer
+ forMode:NSRunLoopCommonModes];
+
+ [super viewWillStartLiveResize];
+}
+
+- (void) viewWillDraw
+{
+ puglDispatchSimpleEvent(puglview, PUGL_UPDATE);
+ [super viewWillDraw];
+}
+
+- (void) resizeTick
+{
+ puglPostRedisplay(puglview);
+}
+
+- (void) timerTick:(NSTimer*)userTimer
+{
+ const NSNumber* userInfo = userTimer.userInfo;
+ const PuglEventTimer ev = {PUGL_TIMER, 0, userInfo.unsignedLongValue};
+
+ puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+}
+
+- (void) viewDidEndLiveResize
+{
+ [super viewDidEndLiveResize];
+ [timer invalidate];
+ timer = NULL;
+}
+
+@end
+
+@interface PuglWindowDelegate : NSObject<NSWindowDelegate>
+{
+ PuglWindow* window;
+}
+
+- (instancetype) initWithPuglWindow:(PuglWindow*)window;
+
+@end
+
+@implementation PuglWindowDelegate
+
+- (instancetype) initWithPuglWindow:(PuglWindow*)puglWindow
+{
+ if ((self = [super init])) {
+ window = puglWindow;
+ }
+
+ return self;
+}
+
+- (BOOL) windowShouldClose:(id)sender
+{
+ (void)sender;
+
+ puglDispatchSimpleEvent(window->puglview, PUGL_CLOSE);
+ return YES;
+}
+
+- (void) windowDidMove:(NSNotification*)notification
+{
+ (void)notification;
+
+ updateViewRect(window->puglview);
+}
+
+- (void) windowDidBecomeKey:(NSNotification*)notification
+{
+ (void)notification;
+
+ PuglEvent ev = {{PUGL_FOCUS_IN, 0}};
+ ev.focus.grab = false;
+ puglDispatchEvent(window->puglview, &ev);
+}
+
+- (void) windowDidResignKey:(NSNotification*)notification
+{
+ (void)notification;
+
+ PuglEvent ev = {{PUGL_FOCUS_OUT, 0}};
+ ev.focus.grab = false;
+ puglDispatchEvent(window->puglview, &ev);
+}
+
+@end
+
+PuglWorldInternals*
+puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type),
+ PuglWorldFlags PUGL_UNUSED(flags))
+{
+ PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
+ 1, sizeof(PuglWorldInternals));
+
+ impl->app = [NSApplication sharedApplication];
+ impl->autoreleasePool = [NSAutoreleasePool new];
+
+ return impl;
+}
+
+void
+puglFreeWorldInternals(PuglWorld* world)
+{
+ [world->impl->autoreleasePool drain];
+ free(world->impl);
+}
+
+void*
+puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world))
+{
+ return NULL;
+}
+
+PuglInternals*
+puglInitViewInternals(void)
+{
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
+}
+
+static NSLayoutConstraint*
+puglConstraint(id item, NSLayoutAttribute attribute, float constant)
+{
+ return [NSLayoutConstraint
+ constraintWithItem: item
+ attribute: attribute
+ relatedBy: NSLayoutRelationGreaterThanOrEqual
+ toItem: nil
+ attribute: NSLayoutAttributeNotAnAttribute
+ multiplier: 1.0
+ constant: constant];
+}
+
+PuglStatus
+puglRealize(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+
+ // Create wrapper view to handle input
+ impl->wrapperView = [PuglWrapperView alloc];
+ impl->wrapperView->puglview = view;
+ impl->wrapperView->userTimers = [[NSMutableDictionary alloc] init];
+ impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init];
+ [impl->wrapperView setAutoresizesSubviews:YES];
+ [impl->wrapperView initWithFrame:
+ NSMakeRect(0, 0, view->frame.width, view->frame.height)];
+ [impl->wrapperView addConstraint:
+ puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, view->minWidth)];
+ [impl->wrapperView addConstraint:
+ puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, view->minHeight)];
+
+ // Create draw view to be rendered to
+ PuglStatus st = PUGL_SUCCESS;
+ if ((st = view->backend->configure(view)) ||
+ (st = view->backend->create(view))) {
+ return st;
+ }
+
+ // Add draw view to wrapper view
+ [impl->wrapperView addSubview:impl->drawView];
+ [impl->wrapperView setHidden:NO];
+ [impl->drawView setHidden:NO];
+
+ if (view->parent) {
+ NSView* pview = (NSView*)view->parent;
+ [pview addSubview:impl->wrapperView];
+ [impl->drawView setHidden:NO];
+ [[impl->drawView window] makeFirstResponder:impl->wrapperView];
+ } else {
+ const NSRect frame = rectToScreen(
+ NSMakeRect(view->frame.x, view->frame.y,
+ view->minWidth, view->minHeight));
+
+ unsigned style = (NSClosableWindowMask |
+ NSTitledWindowMask |
+ NSMiniaturizableWindowMask );
+ if (view->hints[PUGL_RESIZABLE]) {
+ style |= NSResizableWindowMask;
+ }
+
+ PuglWindow* window = [[[PuglWindow alloc]
+ initWithContentRect:frame
+ styleMask:style
+ backing:NSBackingStoreBuffered
+ defer:NO
+ ] retain];
+ [window setPuglview:view];
+
+ if (view->title) {
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:view->title
+ length:strlen(view->title)
+ encoding:NSUTF8StringEncoding];
+
+ [window setTitle:titleString];
+ }
+
+ if (view->minWidth || view->minHeight) {
+ [window setContentMinSize:NSMakeSize(view->minWidth,
+ view->minHeight)];
+ }
+ impl->window = window;
+
+ ((NSWindow*)window).delegate = [[PuglWindowDelegate alloc]
+ initWithPuglWindow:window];
+
+ if (view->minAspectX && view->minAspectY) {
+ [window setContentAspectRatio:NSMakeSize(view->minAspectX,
+ view->minAspectY)];
+ }
+
+ [window setContentView:impl->wrapperView];
+ [view->world->impl->app activateIgnoringOtherApps:YES];
+ [window makeFirstResponder:impl->wrapperView];
+ [window makeKeyAndOrderFront:window];
+ [impl->window setIsVisible:NO];
+ }
+
+ [impl->wrapperView updateTrackingAreas];
+
+ puglDispatchSimpleEvent(view, PUGL_CREATE);
+
+ return 0;
+}
+
+PuglStatus
+puglShowWindow(PuglView* view)
+{
+ if (![view->impl->window isVisible]) {
+ [view->impl->window setIsVisible:YES];
+ [view->impl->drawView setNeedsDisplay: YES];
+ updateViewRect(view);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglHideWindow(PuglView* view)
+{
+ [view->impl->window setIsVisible:NO];
+ return PUGL_SUCCESS;
+}
+
+void
+puglFreeViewInternals(PuglView* view)
+{
+ if (view) {
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+
+ if (view->impl) {
+ [view->impl->wrapperView removeFromSuperview];
+ view->impl->wrapperView->puglview = NULL;
+ if (view->impl->window) {
+ [view->impl->window close];
+ }
+ [view->impl->wrapperView release];
+ if (view->impl->window) {
+ [view->impl->window release];
+ }
+ free(view->impl);
+ }
+ }
+}
+
+PuglStatus
+puglGrabFocus(PuglView* view)
+{
+ NSWindow* window = [view->impl->wrapperView window];
+
+ [window makeKeyWindow];
+ [window makeFirstResponder:view->impl->wrapperView];
+ return PUGL_SUCCESS;
+}
+
+bool
+puglHasFocus(const PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+
+ return ([[impl->wrapperView window] isKeyWindow] &&
+ [[impl->wrapperView window] firstResponder] == impl->wrapperView);
+}
+
+PuglStatus
+puglRequestAttention(PuglView* view)
+{
+ if (![view->impl->window isKeyWindow]) {
+ [view->world->impl->app requestUserAttention:NSInformationalRequest];
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglStartTimer(PuglView* view, uintptr_t id, double timeout)
+{
+ puglStopTimer(view, id);
+
+ NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id];
+
+ NSTimer* timer = [NSTimer timerWithTimeInterval:timeout
+ target:view->impl->wrapperView
+ selector:@selector(timerTick:)
+ userInfo:idNumber
+ repeats:YES];
+
+ [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
+
+ view->impl->wrapperView->userTimers[idNumber] = timer;
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglStopTimer(PuglView* view, uintptr_t id)
+{
+ NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id];
+ NSTimer* timer = view->impl->wrapperView->userTimers[idNumber];
+
+ if (timer) {
+ [view->impl->wrapperView->userTimers removeObjectForKey:timer];
+ [timer invalidate];
+ return PUGL_SUCCESS;
+ }
+
+ return PUGL_UNKNOWN_ERROR;
+}
+
+PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event)
+{
+ if (event->type == PUGL_CLIENT) {
+ PuglWrapperView* wrapper = view->impl->wrapperView;
+ const NSWindow* window = [wrapper window];
+ const NSRect rect = [wrapper frame];
+ const NSPoint center = {NSMidX(rect), NSMidY(rect)};
+
+ NSEvent* nsevent = [NSEvent
+ otherEventWithType:NSApplicationDefined
+ location:center
+ modifierFlags:0
+ timestamp:[[NSProcessInfo processInfo] systemUptime]
+ windowNumber:window.windowNumber
+ context:nil
+ subtype:PUGL_CLIENT
+ data1:(NSInteger)event->client.data1
+ data2:(NSInteger)event->client.data2];
+
+ [view->world->impl->app postEvent:nsevent atStart:false];
+ return PUGL_SUCCESS;
+ }
+
+ return PUGL_UNSUPPORTED_TYPE;
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+PuglStatus
+puglWaitForEvent(PuglView* view)
+{
+ return puglPollEvents(view->world, -1.0);
+}
+#endif
+
+static void
+dispatchClientEvent(PuglWorld* world, NSEvent* ev)
+{
+ NSWindow* win = [ev window];
+ NSPoint loc = [ev locationInWindow];
+ for (size_t i = 0; i < world->numViews; ++i) {
+ PuglView* view = world->views[i];
+ PuglWrapperView* wrapper = view->impl->wrapperView;
+ if ([wrapper window] == win && NSPointInRect(loc, [wrapper frame])) {
+ const PuglEventClient event = {PUGL_CLIENT,
+ 0,
+ (uintptr_t)[ev data1],
+ (uintptr_t)[ev data2]};
+
+ puglDispatchEvent(view, (const PuglEvent*)&event);
+ }
+ }
+}
+
+PuglStatus
+puglUpdate(PuglWorld* world, const double timeout)
+{
+ NSDate* date = ((timeout < 0)
+ ? [NSDate distantFuture]
+ : [NSDate dateWithTimeIntervalSinceNow:timeout]);
+
+ for (NSEvent* ev = NULL;
+ (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask
+ untilDate:date
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES]);) {
+
+ if ([ev type] == NSApplicationDefined && [ev subtype] == PUGL_CLIENT) {
+ dispatchClientEvent(world, ev);
+ }
+
+ [world->impl->app sendEvent: ev];
+
+ if (timeout < 0) {
+ // Now that we've waited and got an event, set the date to now to
+ // avoid looping forever
+ date = [NSDate date];
+ }
+ }
+
+ for (size_t i = 0; i < world->numViews; ++i) {
+ PuglView* const view = world->views[i];
+
+ if ([[view->impl->drawView window] isVisible]) {
+ puglDispatchSimpleEvent(view, PUGL_UPDATE);
+ }
+
+ [view->impl->drawView displayIfNeeded];
+ }
+
+ return PUGL_SUCCESS;
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ return puglDispatchEvents(view->world);
+}
+#endif
+
+double
+puglGetTime(const PuglWorld* world)
+{
+ return (mach_absolute_time() / 1e9) - world->startTime;
+}
+
+PuglStatus
+puglPostRedisplay(PuglView* view)
+{
+ [view->impl->drawView setNeedsDisplay: YES];
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglPostRedisplayRect(PuglView* view, const PuglRect rect)
+{
+ [view->impl->drawView setNeedsDisplayInRect:
+ NSMakeRect(rect.x, rect.y, rect.width, rect.height)];
+
+ return PUGL_SUCCESS;
+}
+
+PuglNativeView
+puglGetNativeWindow(PuglView* view)
+{
+ return (PuglNativeView)view->impl->wrapperView;
+}
+
+PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title)
+{
+ puglSetString(&view->title, title);
+
+ if (view->impl->window) {
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:title
+ length:strlen(title)
+ encoding:NSUTF8StringEncoding];
+
+ [view->impl->window setTitle:titleString];
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetFrame(PuglView* view, const PuglRect frame)
+{
+ PuglInternals* const impl = view->impl;
+
+ // Update view frame to exactly the requested frame in Pugl coordinates
+ view->frame = frame;
+
+ const NSRect rect = NSMakeRect(frame.x, frame.y, frame.width, frame.height);
+ if (impl->window) {
+ // Resize window to fit new content rect
+ const NSRect windowFrame = [
+ impl->window frameRectForContentRect:rectToScreen(rect)];
+
+ [impl->window setFrame:windowFrame display:NO];
+ }
+
+ // Resize views
+ const NSRect drawRect = NSMakeRect(0, 0, frame.width, frame.height);
+ [impl->wrapperView setFrame:(impl->window ? drawRect : rect)];
+ [impl->drawView setFrame:drawRect];
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetMinSize(PuglView* const view, const int width, const int height)
+{
+ view->minWidth = width;
+ view->minHeight = height;
+
+ if (view->impl->window && (view->minWidth || view->minHeight)) {
+ [view->impl->window
+ setContentMinSize:NSMakeSize(view->minWidth, view->minHeight)];
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetAspectRatio(PuglView* const view,
+ const int minX,
+ const int minY,
+ const int maxX,
+ const int maxY)
+{
+ view->minAspectX = minX;
+ view->minAspectY = minY;
+ view->maxAspectX = maxX;
+ view->maxAspectY = maxY;
+
+ if (view->impl->window && view->minAspectX && view->minAspectY) {
+ [view->impl->window setContentAspectRatio:NSMakeSize(view->minAspectX,
+ view->minAspectY)];
+ }
+
+ return PUGL_SUCCESS;
+}
+
+const void*
+puglGetClipboard(PuglView* const view,
+ const char** const type,
+ size_t* const len)
+{
+ NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard];
+
+ if ([[pasteboard types] containsObject:NSStringPboardType]) {
+ const NSString* str = [pasteboard stringForType:NSStringPboardType];
+ const char* utf8 = [str UTF8String];
+
+ puglSetBlob(&view->clipboard, utf8, strlen(utf8) + 1);
+ }
+
+ return puglGetInternalClipboard(view, type, len);
+}
+
+PuglStatus
+puglSetClipboard(PuglView* const view,
+ const char* const type,
+ const void* const data,
+ const size_t len)
+{
+ NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard];
+ const char* const str = (const char*)data;
+
+ PuglStatus st = puglSetInternalClipboard(view, type, data, len);
+ if (st) {
+ return st;
+ }
+
+ NSString* nsString = [NSString stringWithUTF8String:str];
+ if (nsString) {
+ [pasteboard
+ declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil]
+ owner:nil];
+
+ [pasteboard setString:nsString forType:NSStringPboardType];
+
+ return PUGL_SUCCESS;
+ }
+
+ return PUGL_UNKNOWN_ERROR;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/mac_cairo.m b/subprojects/d2tk/pugl/pugl/detail/mac_cairo.m
new file mode 100644
index 00000000..51c1c13b
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/mac_cairo.m
@@ -0,0 +1,155 @@
+/*
+ Copyright 2019 David Robillard <http://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 mac_cairo.m Cairo graphics backend for MacOS.
+*/
+
+#include "pugl/detail/implementation.h"
+#include "pugl/detail/mac.h"
+#include "pugl/pugl_cairo.h"
+#include "pugl/pugl_stub.h"
+
+#include <cairo-quartz.h>
+
+#import <Cocoa/Cocoa.h>
+
+#include <assert.h>
+
+@interface PuglCairoView : NSView
+{
+@public
+ PuglView* puglview;
+ cairo_surface_t* surface;
+ cairo_t* cr;
+}
+
+@end
+
+@implementation PuglCairoView
+
+- (id) initWithFrame:(NSRect)frame
+{
+ return (self = [super initWithFrame:frame]);
+}
+
+- (void) resizeWithOldSuperviewSize:(NSSize)oldSize
+{
+ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
+
+ [super resizeWithOldSuperviewSize:oldSize];
+ [wrapper setReshaped];
+}
+
+- (void) drawRect:(NSRect)rect
+{
+ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
+ [wrapper dispatchExpose:rect];
+}
+
+@end
+
+static PuglStatus
+puglMacCairoCreate(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+ PuglCairoView* drawView = [PuglCairoView alloc];
+
+ drawView->puglview = view;
+ [drawView initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)];
+ if (view->hints[PUGL_RESIZABLE]) {
+ [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ } else {
+ [drawView setAutoresizingMask:NSViewNotSizable];
+ }
+
+ impl->drawView = drawView;
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacCairoDestroy(PuglView* view)
+{
+ PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
+
+ [drawView removeFromSuperview];
+ [drawView release];
+
+ view->impl->drawView = nil;
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacCairoEnter(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
+ if (!expose) {
+ return PUGL_SUCCESS;
+ }
+
+ assert(!drawView->surface);
+ assert(!drawView->cr);
+
+ CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
+
+ drawView->surface = cairo_quartz_surface_create_for_cg_context(
+ context, view->frame.width, view->frame.height);
+
+ drawView->cr = cairo_create(drawView->surface);
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacCairoLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView;
+ if (!expose) {
+ return PUGL_SUCCESS;
+ }
+
+ assert(drawView->surface);
+ assert(drawView->cr);
+
+ CGContextRef context = cairo_quartz_surface_get_cg_context(drawView->surface);
+
+ cairo_destroy(drawView->cr);
+ cairo_surface_destroy(drawView->surface);
+ drawView->cr = NULL;
+ drawView->surface = NULL;
+
+ CGContextFlush(context);
+
+ return PUGL_SUCCESS;
+}
+
+static void*
+puglMacCairoGetContext(PuglView* view)
+{
+ return ((PuglCairoView*)view->impl->drawView)->cr;
+}
+
+const PuglBackend* puglCairoBackend(void)
+{
+ static const PuglBackend backend = {puglStubConfigure,
+ puglMacCairoCreate,
+ puglMacCairoDestroy,
+ puglMacCairoEnter,
+ puglMacCairoLeave,
+ puglMacCairoGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/mac_gl.m b/subprojects/d2tk/pugl/pugl/detail/mac_gl.m
new file mode 100644
index 00000000..eda43711
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/mac_gl.m
@@ -0,0 +1,177 @@
+/*
+ Copyright 2019-2020 David Robillard <http://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 mac_gl.m OpenGL graphics backend for MacOS.
+*/
+
+#include "pugl/detail/implementation.h"
+#include "pugl/detail/mac.h"
+#include "pugl/pugl_gl.h"
+#include "pugl/pugl_stub.h"
+
+#ifndef __MAC_10_10
+# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core
+#endif
+
+@interface PuglOpenGLView : NSOpenGLView
+{
+@public
+ PuglView* puglview;
+}
+
+@end
+
+@implementation PuglOpenGLView
+
+- (id) initWithFrame:(NSRect)frame
+{
+ const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE];
+ const unsigned samples = (unsigned)puglview->hints[PUGL_SAMPLES];
+ const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR];
+ const unsigned profile = ((compat || major < 3)
+ ? NSOpenGLProfileVersionLegacy
+ : (major >= 4
+ ? NSOpenGLProfileVersion4_1Core
+ : NSOpenGLProfileVersion3_2Core));
+
+ NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAOpenGLProfile, profile,
+ NSOpenGLPFAColorSize, 32,
+ NSOpenGLPFADepthSize, 32,
+ NSOpenGLPFAMultisample, samples ? 1 : 0,
+ NSOpenGLPFASampleBuffers, samples ? 1 : 0,
+ NSOpenGLPFASamples, samples,
+ 0};
+
+ NSOpenGLPixelFormat* pixelFormat = [
+ [NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs];
+
+ if (pixelFormat) {
+ self = [super initWithFrame:frame pixelFormat:pixelFormat];
+ [pixelFormat release];
+ } else {
+ self = [super initWithFrame:frame];
+ }
+
+ if (self) {
+ [[self openGLContext] makeCurrentContext];
+ [self reshape];
+ }
+ return self;
+}
+
+- (void) reshape
+{
+ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
+
+ [super reshape];
+ [wrapper setReshaped];
+}
+
+- (void) drawRect:(NSRect)rect
+{
+ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
+ [wrapper dispatchExpose:rect];
+}
+
+@end
+
+static PuglStatus
+puglMacGlCreate(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+ PuglOpenGLView* drawView = [PuglOpenGLView alloc];
+ const NSRect rect = NSMakeRect(
+ 0, 0, view->frame.width, view->frame.height);
+
+ drawView->puglview = view;
+ [drawView initWithFrame:rect];
+ if (view->hints[PUGL_RESIZABLE]) {
+ [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ } else {
+ [drawView setAutoresizingMask:NSViewNotSizable];
+ }
+
+ impl->drawView = drawView;
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacGlDestroy(PuglView* view)
+{
+ PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;
+
+ [drawView removeFromSuperview];
+ [drawView release];
+
+ view->impl->drawView = nil;
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacGlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose))
+{
+ PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;
+
+ [[drawView openGLContext] makeCurrentContext];
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacGlLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView;
+
+ if (expose) {
+ [[drawView openGLContext] flushBuffer];
+ }
+
+ [NSOpenGLContext clearCurrentContext];
+
+ return PUGL_SUCCESS;
+}
+
+PuglGlFunc
+puglGetProcAddress(const char *name)
+{
+ CFBundleRef framework =
+ CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+
+ CFStringRef symbol = CFStringCreateWithCString(
+ kCFAllocatorDefault, name, kCFStringEncodingASCII);
+
+ PuglGlFunc func = (PuglGlFunc)CFBundleGetFunctionPointerForName(
+ framework, symbol);
+
+ CFRelease(symbol);
+
+ return func;
+}
+
+const PuglBackend* puglGlBackend(void)
+{
+ static const PuglBackend backend = {puglStubConfigure,
+ puglMacGlCreate,
+ puglMacGlDestroy,
+ puglMacGlEnter,
+ puglMacGlLeave,
+ puglStubGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/mac_stub.m b/subprojects/d2tk/pugl/pugl/detail/mac_stub.m
new file mode 100644
index 00000000..71a54b88
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/mac_stub.m
@@ -0,0 +1,95 @@
+/*
+ Copyright 2019-2020 David Robillard <http://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 mac_stub.m Stub graphics backend for MacOS.
+*/
+
+#include "pugl/detail/implementation.h"
+#include "pugl/detail/mac.h"
+#include "pugl/pugl_stub.h"
+
+#import <Cocoa/Cocoa.h>
+
+@interface PuglStubView : NSView
+{
+@public
+ PuglView* puglview;
+}
+
+@end
+
+@implementation PuglStubView
+
+- (void) resizeWithOldSuperviewSize:(NSSize)oldSize
+{
+ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
+
+ [super resizeWithOldSuperviewSize:oldSize];
+ [wrapper setReshaped];
+}
+
+- (void) drawRect:(NSRect)rect
+{
+ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
+
+ [wrapper dispatchExpose:rect];
+}
+
+@end
+
+static PuglStatus
+puglMacStubCreate(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+ PuglStubView* drawView = [PuglStubView alloc];
+
+ drawView->puglview = view;
+ [drawView initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)];
+ if (view->hints[PUGL_RESIZABLE]) {
+ [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ } else {
+ [drawView setAutoresizingMask:NSViewNotSizable];
+ }
+
+ impl->drawView = drawView;
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglMacStubDestroy(PuglView* view)
+{
+ PuglStubView* const drawView = (PuglStubView*)view->impl->drawView;
+
+ [drawView removeFromSuperview];
+ [drawView release];
+
+ view->impl->drawView = nil;
+ return PUGL_SUCCESS;
+}
+
+const PuglBackend*
+puglStubBackend(void)
+{
+ static const PuglBackend backend = {puglStubConfigure,
+ puglMacStubCreate,
+ puglMacStubDestroy,
+ puglStubEnter,
+ puglStubLeave,
+ puglStubGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/types.h b/subprojects/d2tk/pugl/pugl/detail/types.h
new file mode 100644
index 00000000..eb450e14
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/types.h
@@ -0,0 +1,113 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 types.h Shared internal type definitions.
+*/
+
+#ifndef PUGL_DETAIL_TYPES_H
+#define PUGL_DETAIL_TYPES_H
+
+#include "pugl/pugl.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+// Unused parameter macro to suppresses warnings and make it impossible to use
+#if defined(__cplusplus)
+# define PUGL_UNUSED(name)
+#elif defined(__GNUC__)
+# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__))
+#else
+# define PUGL_UNUSED(name) name
+#endif
+
+/** Platform-specific world internals. */
+typedef struct PuglWorldInternalsImpl PuglWorldInternals;
+
+/** Platform-specific view internals. */
+typedef struct PuglInternalsImpl PuglInternals;
+
+/** View hints. */
+typedef int PuglHints[PUGL_NUM_VIEW_HINTS];
+
+/** Blob of arbitrary data. */
+typedef struct {
+ void* data; //!< Dynamically allocated data
+ size_t len; //!< Length of data in bytes
+} PuglBlob;
+
+/** Cross-platform view definition. */
+struct PuglViewImpl {
+ PuglWorld* world;
+ const PuglBackend* backend;
+ PuglInternals* impl;
+ PuglHandle handle;
+ PuglEventFunc eventFunc;
+ char* title;
+ PuglBlob clipboard;
+ PuglNativeView parent;
+ uintptr_t transientParent;
+ PuglHints hints;
+ PuglRect frame;
+ PuglEventConfigure lastConfigure;
+ int minWidth;
+ int minHeight;
+ int minAspectX;
+ int minAspectY;
+ int maxAspectX;
+ int maxAspectY;
+ bool visible;
+};
+
+/** Cross-platform world definition. */
+struct PuglWorldImpl {
+ PuglWorldInternals* impl;
+ PuglWorldHandle handle;
+ PuglLogFunc logFunc;
+ char* className;
+ double startTime;
+ size_t numViews;
+ PuglView** views;
+ PuglLogLevel logLevel;
+};
+
+/** Opaque surface used by graphics backend. */
+typedef void PuglSurface;
+
+/** Graphics backend interface. */
+struct PuglBackendImpl {
+ /** Get visual information from display and setup view as necessary. */
+ PuglStatus (*configure)(PuglView*);
+
+ /** Create surface and drawing context. */
+ PuglStatus (*create)(PuglView*);
+
+ /** Destroy surface and drawing context. */
+ PuglStatus (*destroy)(PuglView*);
+
+ /** Enter drawing context, for drawing if expose is non-null. */
+ PuglStatus (*enter)(PuglView*, const PuglEventExpose*);
+
+ /** Leave drawing context, after drawing if expose is non-null. */
+ PuglStatus (*leave)(PuglView*, const PuglEventExpose*);
+
+ /** Return the puglGetContext() handle for the application, if any. */
+ void* (*getContext)(PuglView*);
+};
+
+#endif // PUGL_DETAIL_TYPES_H
diff --git a/subprojects/d2tk/pugl/pugl/detail/win.c b/subprojects/d2tk/pugl/pugl/detail/win.c
new file mode 100644
index 00000000..44ba6cd9
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/win.c
@@ -0,0 +1,1084 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 win.c Windows implementation.
+*/
+
+#include "pugl/detail/win.h"
+
+#include "pugl/detail/implementation.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_stub.h"
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wctype.h>
+
+#ifndef WM_MOUSEWHEEL
+# define WM_MOUSEWHEEL 0x020A
+#endif
+#ifndef WM_MOUSEHWHEEL
+# define WM_MOUSEHWHEEL 0x020E
+#endif
+#ifndef WHEEL_DELTA
+# define WHEEL_DELTA 120
+#endif
+#ifndef GWLP_USERDATA
+# define GWLP_USERDATA (-21)
+#endif
+
+#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50)
+#define PUGL_LOCAL_MARK_MSG (WM_USER + 51)
+#define PUGL_LOCAL_CLIENT_MSG (WM_USER + 52)
+#define PUGL_RESIZE_TIMER_ID 9461
+#define PUGL_USER_TIMER_MIN 9470
+
+typedef BOOL (WINAPI *PFN_SetProcessDPIAware)(void);
+
+LRESULT CALLBACK
+wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+static wchar_t*
+puglUtf8ToWideChar(const char* const utf8)
+{
+ const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
+ if (len > 0) {
+ wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len);
+ return result;
+ }
+
+ return NULL;
+}
+
+static char*
+puglWideCharToUtf8(const wchar_t* const wstr, size_t* len)
+{
+ int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
+ if (n > 0) {
+ char* result = (char*)calloc((size_t)n, sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL);
+ *len = (size_t)n;
+ return result;
+ }
+
+ return NULL;
+}
+
+static bool
+puglRegisterWindowClass(const char* name)
+{
+ WNDCLASSEX wc = { 0 };
+ if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) {
+ return true; // Already registered
+ }
+
+ wc.cbSize = sizeof(wc);
+ wc.style = CS_OWNDC;
+ wc.lpfnWndProc = wndProc;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wc.lpszClassName = name;
+
+ return RegisterClassEx(&wc);
+}
+
+PuglWorldInternals*
+puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type),
+ PuglWorldFlags PUGL_UNUSED(flags))
+{
+ PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
+ 1, sizeof(PuglWorldInternals));
+ if (!impl) {
+ return NULL;
+ }
+
+ HMODULE user32 = LoadLibrary("user32.dll");
+ if (user32) {
+ PFN_SetProcessDPIAware SetProcessDPIAware =
+ (PFN_SetProcessDPIAware)GetProcAddress(
+ user32, "SetProcessDPIAware");
+ if (SetProcessDPIAware) {
+ SetProcessDPIAware();
+ }
+
+ FreeLibrary(user32);
+ }
+
+ LARGE_INTEGER frequency;
+ QueryPerformanceFrequency(&frequency);
+ impl->timerFrequency = (double)frequency.QuadPart;
+
+ return impl;
+}
+
+void*
+puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world))
+{
+ return GetModuleHandle(NULL);
+}
+
+PuglInternals*
+puglInitViewInternals(void)
+{
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
+}
+
+static PuglStatus
+puglPollWinEvents(PuglWorld* world, const double timeout)
+{
+ (void)world;
+
+ if (timeout < 0) {
+ WaitMessage();
+ } else {
+ MsgWaitForMultipleObjects(
+ 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS);
+ }
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglRealize(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+
+ // Get refresh rate for resize draw timer
+ DEVMODEA devMode = {0};
+ EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);
+ view->impl->refreshRate = devMode.dmDisplayFrequency;
+
+ // Register window class if necessary
+ if (!puglRegisterWindowClass(view->world->className)) {
+ return PUGL_REGISTRATION_FAILED;
+ }
+
+ if (!view->backend || !view->backend->configure) {
+ return PUGL_BAD_BACKEND;
+ }
+
+ PuglStatus st = view->backend->configure(view);
+ if (st) {
+ return PUGL_SET_FORMAT_FAILED;
+ } else if ((st = view->backend->create(view))) {
+ return PUGL_CREATE_CONTEXT_FAILED;
+ }
+
+ if (view->title) {
+ puglSetWindowTitle(view, view->title);
+ }
+
+ puglSetFrame(view, view->frame);
+ SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view);
+
+ puglDispatchSimpleEvent(view, PUGL_CREATE);
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglShowWindow(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+
+ ShowWindow(impl->hwnd, SW_SHOWNORMAL);
+ SetFocus(impl->hwnd);
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglHideWindow(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+
+ ShowWindow(impl->hwnd, SW_HIDE);
+ return PUGL_SUCCESS;
+}
+
+void
+puglFreeViewInternals(PuglView* view)
+{
+ if (view) {
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+
+ ReleaseDC(view->impl->hwnd, view->impl->hdc);
+ DestroyWindow(view->impl->hwnd);
+ free(view->impl);
+ }
+}
+
+void
+puglFreeWorldInternals(PuglWorld* world)
+{
+ UnregisterClass(world->className, NULL);
+ free(world->impl);
+}
+
+static PuglKey
+keySymToSpecial(WPARAM sym)
+{
+ // clang-format off
+ switch (sym) {
+ case VK_F1: return PUGL_KEY_F1;
+ case VK_F2: return PUGL_KEY_F2;
+ case VK_F3: return PUGL_KEY_F3;
+ case VK_F4: return PUGL_KEY_F4;
+ case VK_F5: return PUGL_KEY_F5;
+ case VK_F6: return PUGL_KEY_F6;
+ case VK_F7: return PUGL_KEY_F7;
+ case VK_F8: return PUGL_KEY_F8;
+ case VK_F9: return PUGL_KEY_F9;
+ case VK_F10: return PUGL_KEY_F10;
+ case VK_F11: return PUGL_KEY_F11;
+ case VK_F12: return PUGL_KEY_F12;
+ case VK_BACK: return PUGL_KEY_BACKSPACE;
+ case VK_DELETE: return PUGL_KEY_DELETE;
+ case VK_LEFT: return PUGL_KEY_LEFT;
+ case VK_UP: return PUGL_KEY_UP;
+ case VK_RIGHT: return PUGL_KEY_RIGHT;
+ case VK_DOWN: return PUGL_KEY_DOWN;
+ case VK_PRIOR: return PUGL_KEY_PAGE_UP;
+ case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
+ case VK_HOME: return PUGL_KEY_HOME;
+ case VK_END: return PUGL_KEY_END;
+ case VK_INSERT: return PUGL_KEY_INSERT;
+ case VK_SHIFT:
+ case VK_LSHIFT: return PUGL_KEY_SHIFT_L;
+ case VK_RSHIFT: return PUGL_KEY_SHIFT_R;
+ case VK_CONTROL:
+ case VK_LCONTROL: return PUGL_KEY_CTRL_L;
+ case VK_RCONTROL: return PUGL_KEY_CTRL_R;
+ case VK_MENU:
+ case VK_LMENU: return PUGL_KEY_ALT_L;
+ case VK_RMENU: return PUGL_KEY_ALT_R;
+ case VK_LWIN: return PUGL_KEY_SUPER_L;
+ case VK_RWIN: return PUGL_KEY_SUPER_R;
+ case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK;
+ case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK;
+ case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK;
+ case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN;
+ case VK_PAUSE: return PUGL_KEY_PAUSE;
+ }
+ // clang-format on
+
+ return (PuglKey)0;
+}
+
+static uint32_t
+getModifiers(void)
+{
+ // clang-format off
+ return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) |
+ ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) |
+ ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) |
+ ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) |
+ ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u));
+ // clang-format on
+}
+
+static void
+initMouseEvent(PuglEvent* event,
+ PuglView* view,
+ int button,
+ bool press,
+ LPARAM lParam)
+{
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ ClientToScreen(view->impl->hwnd, &pt);
+
+ if (press) {
+ SetCapture(view->impl->hwnd);
+ } else {
+ ReleaseCapture();
+ }
+
+ event->button.time = GetMessageTime() / 1e3;
+ event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE;
+ event->button.x = GET_X_LPARAM(lParam);
+ event->button.y = GET_Y_LPARAM(lParam);
+ event->button.xRoot = pt.x;
+ event->button.yRoot = pt.y;
+ event->button.state = getModifiers();
+ event->button.button = (uint32_t)button;
+}
+
+static void
+initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam)
+{
+ POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ ScreenToClient(view->impl->hwnd, &pt);
+
+ event->scroll.time = GetMessageTime() / 1e3;
+ event->scroll.type = PUGL_SCROLL;
+ event->scroll.x = pt.x;
+ event->scroll.y = pt.y;
+ event->scroll.xRoot = GET_X_LPARAM(lParam);
+ event->scroll.yRoot = GET_Y_LPARAM(lParam);
+ event->scroll.state = getModifiers();
+ event->scroll.dx = 0;
+ event->scroll.dy = 0;
+}
+
+/** Return the code point for buf, or the replacement character on error. */
+static uint32_t
+puglDecodeUTF16(const wchar_t* buf, const int len)
+{
+ const uint32_t c0 = buf[0];
+ const uint32_t c1 = buf[0];
+ if (c0 >= 0xD800 && c0 < 0xDC00) {
+ if (len < 2) {
+ return 0xFFFD; // Surrogate, but length is only 1
+ } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) {
+ return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000;
+ }
+
+ return 0xFFFD; // Unpaired surrogates
+ }
+
+ return c0;
+}
+
+static void
+initKeyEvent(PuglEventKey* event,
+ PuglView* view,
+ bool press,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ POINT rpos = { 0, 0 };
+ GetCursorPos(&rpos);
+
+ POINT cpos = { rpos.x, rpos.y };
+ ScreenToClient(view->impl->hwnd, &rpos);
+
+ const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16);
+ const unsigned vkey = ((wParam == VK_SHIFT)
+ ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX)
+ : (unsigned)wParam);
+
+ const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC);
+ const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR);
+ const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1;
+ const bool ext = lParam & 0x01000000;
+
+ event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
+ event->time = GetMessageTime() / 1e3;
+ event->state = getModifiers();
+ event->xRoot = rpos.x;
+ event->yRoot = rpos.y;
+ event->x = cpos.x;
+ event->y = cpos.y;
+ event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16);
+ event->key = 0;
+
+ const PuglKey special = keySymToSpecial(vkey);
+ if (special) {
+ if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) {
+ event->key = special + 1u; // Right hand key
+ } else {
+ event->key = special;
+ }
+ } else if (!dead) {
+ // Translate unshifted key
+ BYTE keyboardState[256] = {0};
+ wchar_t buf[5] = {0};
+
+ event->key = puglDecodeUTF16(
+ buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2));
+ }
+}
+
+static void
+initCharEvent(PuglEvent* event, PuglView* view, WPARAM wParam, LPARAM lParam)
+{
+ const wchar_t utf16[2] = { wParam & 0xFFFF, (wParam >> 16) & 0xFFFF };
+
+ initKeyEvent(&event->key, view, true, wParam, lParam);
+ event->type = PUGL_TEXT;
+ event->text.character = puglDecodeUTF16(utf16, 2);
+
+ if (!WideCharToMultiByte(
+ CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) {
+ memset(event->text.string, 0, 8);
+ }
+}
+
+static bool
+ignoreKeyEvent(PuglView* view, LPARAM lParam)
+{
+ return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30));
+}
+
+static RECT
+handleConfigure(PuglView* view, PuglEvent* event)
+{
+ RECT rect;
+ GetClientRect(view->impl->hwnd, &rect);
+ MapWindowPoints(view->impl->hwnd,
+ view->parent ? (HWND)view->parent : HWND_DESKTOP,
+ (LPPOINT)&rect,
+ 2);
+
+ const LONG width = rect.right - rect.left;
+ const LONG height = rect.bottom - rect.top;
+
+ view->frame.x = rect.left;
+ view->frame.y = rect.top;
+
+ event->configure.type = PUGL_CONFIGURE;
+ event->configure.x = view->frame.x;
+ event->configure.y = view->frame.y;
+ event->configure.width = width;
+ event->configure.height = height;
+
+ if (view->frame.width != width || view->frame.height != height) {
+ view->frame.width = width;
+ view->frame.height = height;
+ }
+
+ return rect;
+}
+
+static void
+handleCrossing(PuglView* view, const PuglEventType type, POINT pos)
+{
+ POINT root_pos = pos;
+ ClientToScreen(view->impl->hwnd, &root_pos);
+
+ const PuglEventCrossing ev = {
+ type,
+ 0,
+ GetMessageTime() / 1e3,
+ (double)pos.x,
+ (double)pos.y,
+ (double)root_pos.x,
+ (double)root_pos.y,
+ getModifiers(),
+ PUGL_CROSSING_NORMAL,
+ };
+
+ puglDispatchEvent(view, (const PuglEvent*)&ev);
+}
+
+static void
+constrainAspect(const PuglView* const view,
+ RECT* const size,
+ const WPARAM wParam)
+{
+ const float minA = (float)view->minAspectX / (float)view->minAspectY;
+ const float maxA = (float)view->maxAspectX / (float)view->maxAspectY;
+ const int w = size->right - size->left;
+ const int h = size->bottom - size->top;
+ const float a = (float)w / (float)h;
+
+ switch (wParam) {
+ case WMSZ_TOP:
+ size->top = (a < minA ? (LONG)(size->bottom - w * minA) :
+ a > maxA ? (LONG)(size->bottom - w * maxA) :
+ size->top);
+ break;
+ case WMSZ_TOPRIGHT:
+ case WMSZ_RIGHT:
+ case WMSZ_BOTTOMRIGHT:
+ size->right = (a < minA ? (LONG)(size->left + h * minA) :
+ a > maxA ? (LONG)(size->left + h * maxA) :
+ size->right);
+ break;
+ case WMSZ_BOTTOM:
+ size->bottom = (a < minA ? (LONG)(size->top + w * minA) :
+ a > maxA ? (LONG)(size->top + w * maxA) :
+ size->bottom);
+ break;
+ case WMSZ_BOTTOMLEFT:
+ case WMSZ_LEFT:
+ case WMSZ_TOPLEFT:
+ size->left = (a < minA ? (LONG)(size->right - h * minA) :
+ a > maxA ? (LONG)(size->right - h * maxA) :
+ size->left);
+ break;
+ }
+}
+
+static LRESULT
+handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PuglEvent event;
+ void* dummy_ptr = NULL;
+ RECT rect;
+ MINMAXINFO* mmi;
+ POINT pt;
+
+ memset(&event, 0, sizeof(event));
+
+ event.any.type = PUGL_NOTHING;
+ if (InSendMessageEx(dummy_ptr)) {
+ event.any.flags |= PUGL_IS_SEND_EVENT;
+ }
+
+ switch (message) {
+ case WM_SHOWWINDOW:
+ if (wParam) {
+ handleConfigure(view, &event);
+ puglDispatchEvent(view, &event);
+ event.type = PUGL_NOTHING;
+
+ RedrawWindow(view->impl->hwnd, NULL, NULL,
+ RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
+ }
+
+ if ((bool)wParam != view->visible) {
+ view->visible = wParam;
+ event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP;
+ }
+ break;
+ case WM_SIZE:
+ handleConfigure(view, &event);
+ InvalidateRect(view->impl->hwnd, NULL, false);
+ break;
+ case WM_SIZING:
+ if (view->minAspectX) {
+ constrainAspect(view, (RECT*)lParam, wParam);
+ return TRUE;
+ }
+ break;
+ case WM_ENTERSIZEMOVE:
+ case WM_ENTERMENULOOP:
+ view->impl->resizing = true;
+ SetTimer(view->impl->hwnd,
+ PUGL_RESIZE_TIMER_ID,
+ 1000 / view->impl->refreshRate,
+ NULL);
+ break;
+ case WM_TIMER:
+ if (wParam == PUGL_RESIZE_TIMER_ID) {
+ RedrawWindow(view->impl->hwnd, NULL, NULL,
+ RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
+ } else if (wParam >= PUGL_USER_TIMER_MIN) {
+ const PuglEventTimer ev = {PUGL_TIMER, 0, wParam - PUGL_USER_TIMER_MIN};
+ puglDispatchEvent(view, (const PuglEvent*)&ev);
+ }
+ break;
+ case WM_EXITSIZEMOVE:
+ case WM_EXITMENULOOP:
+ KillTimer(view->impl->hwnd, PUGL_RESIZE_TIMER_ID);
+ view->impl->resizing = false;
+ puglPostRedisplay(view);
+ break;
+ case WM_GETMINMAXINFO:
+ mmi = (MINMAXINFO*)lParam;
+ mmi->ptMinTrackSize.x = view->minWidth;
+ mmi->ptMinTrackSize.y = view->minHeight;
+ break;
+ case WM_PAINT:
+ GetUpdateRect(view->impl->hwnd, &rect, false);
+ event.expose.type = PUGL_EXPOSE;
+ event.expose.x = rect.left;
+ event.expose.y = rect.top;
+ event.expose.width = rect.right - rect.left;
+ event.expose.height = rect.bottom - rect.top;
+ event.expose.count = 0;
+ break;
+ case WM_ERASEBKGND:
+ return true;
+ case WM_MOUSEMOVE:
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(lParam);
+
+ if (!view->impl->mouseTracked) {
+ TRACKMOUSEEVENT tme = {0};
+
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = view->impl->hwnd;
+ TrackMouseEvent(&tme);
+
+ handleCrossing(view, PUGL_POINTER_IN, pt);
+ view->impl->mouseTracked = true;
+ }
+
+ ClientToScreen(view->impl->hwnd, &pt);
+ event.motion.type = PUGL_MOTION;
+ event.motion.time = GetMessageTime() / 1e3;
+ event.motion.x = GET_X_LPARAM(lParam);
+ event.motion.y = GET_Y_LPARAM(lParam);
+ event.motion.xRoot = pt.x;
+ event.motion.yRoot = pt.y;
+ event.motion.state = getModifiers();
+ event.motion.isHint = false;
+ break;
+ case WM_MOUSELEAVE:
+ GetCursorPos(&pt);
+ ScreenToClient(view->impl->hwnd, &pt);
+ handleCrossing(view, PUGL_POINTER_OUT, pt);
+ view->impl->mouseTracked = false;
+ break;
+ case WM_LBUTTONDOWN:
+ initMouseEvent(&event, view, 1, true, lParam);
+ break;
+ case WM_MBUTTONDOWN:
+ initMouseEvent(&event, view, 2, true, lParam);
+ break;
+ case WM_RBUTTONDOWN:
+ initMouseEvent(&event, view, 3, true, lParam);
+ break;
+ case WM_LBUTTONUP:
+ initMouseEvent(&event, view, 1, false, lParam);
+ break;
+ case WM_MBUTTONUP:
+ initMouseEvent(&event, view, 2, false, lParam);
+ break;
+ case WM_RBUTTONUP:
+ initMouseEvent(&event, view, 3, false, lParam);
+ break;
+ case WM_MOUSEWHEEL:
+ initScrollEvent(&event, view, lParam);
+ event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
+ break;
+ case WM_MOUSEHWHEEL:
+ initScrollEvent(&event, view, lParam);
+ event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
+ break;
+ case WM_KEYDOWN:
+ if (!ignoreKeyEvent(view, lParam)) {
+ initKeyEvent(&event.key, view, true, wParam, lParam);
+ }
+ break;
+ case WM_KEYUP:
+ initKeyEvent(&event.key, view, false, wParam, lParam);
+ break;
+ case WM_CHAR:
+ initCharEvent(&event, view, wParam, lParam);
+ break;
+ case WM_SETFOCUS:
+ event.type = PUGL_FOCUS_IN;
+ break;
+ case WM_KILLFOCUS:
+ event.type = PUGL_FOCUS_OUT;
+ break;
+ case WM_SYSKEYDOWN:
+ initKeyEvent(&event.key, view, true, wParam, lParam);
+ break;
+ case WM_SYSKEYUP:
+ initKeyEvent(&event.key, view, false, wParam, lParam);
+ break;
+ case WM_SYSCHAR:
+ return TRUE;
+ case PUGL_LOCAL_CLIENT_MSG:
+ event.client.type = PUGL_CLIENT;
+ event.client.data1 = (uintptr_t)wParam;
+ event.client.data2 = (uintptr_t)lParam;
+ break;
+ case WM_QUIT:
+ case PUGL_LOCAL_CLOSE_MSG:
+ event.any.type = PUGL_CLOSE;
+ break;
+ default:
+ return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
+ }
+
+ puglDispatchEvent(view, &event);
+
+ return 0;
+}
+
+PuglStatus
+puglGrabFocus(PuglView* view)
+{
+ SetFocus(view->impl->hwnd);
+ return PUGL_SUCCESS;
+}
+
+bool
+puglHasFocus(const PuglView* view)
+{
+ return GetFocus() == view->impl->hwnd;
+}
+
+PuglStatus
+puglRequestAttention(PuglView* view)
+{
+ FLASHWINFO info = {sizeof(FLASHWINFO),
+ view->impl->hwnd,
+ FLASHW_ALL|FLASHW_TIMERNOFG,
+ 1,
+ 0};
+
+ FlashWindowEx(&info);
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglStartTimer(PuglView* view, uintptr_t id, double timeout)
+{
+ const UINT msec = (UINT)floor(timeout * 1000.0);
+
+ return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL)
+ ? PUGL_SUCCESS
+ : PUGL_UNKNOWN_ERROR);
+}
+
+PuglStatus
+puglStopTimer(PuglView* view, uintptr_t id)
+{
+ return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id)
+ ? PUGL_SUCCESS
+ : PUGL_UNKNOWN_ERROR);
+}
+
+PuglStatus
+puglSendEvent(PuglView* view, const PuglEvent* event)
+{
+ if (event->type == PUGL_CLIENT) {
+ PostMessage(view->impl->hwnd,
+ PUGL_LOCAL_CLIENT_MSG,
+ (WPARAM)event->client.data1,
+ (LPARAM)event->client.data2);
+
+ return PUGL_SUCCESS;
+ }
+
+ return PUGL_UNSUPPORTED_TYPE;
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+PuglStatus
+puglWaitForEvent(PuglView* PUGL_UNUSED(view))
+{
+ WaitMessage();
+ return PUGL_SUCCESS;
+}
+#endif
+
+static PuglStatus
+puglDispatchViewEvents(PuglView* view)
+{
+ /* Windows has no facility to process only currently queued messages, which
+ causes the event loop to run forever in cases like mouse movement where
+ the queue is constantly being filled with new messages. To work around
+ this, we post a message to ourselves before starting, record its time
+ when it is received, then break the loop on the first message that was
+ created afterwards. */
+
+ long markTime = 0;
+ MSG msg;
+ while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
+ if (msg.message == PUGL_LOCAL_MARK_MSG) {
+ markTime = GetMessageTime();
+ } else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if (markTime != 0 && GetMessageTime() > markTime) {
+ break;
+ }
+ }
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglDispatchWinEvents(PuglWorld* world)
+{
+ for (size_t i = 0; i < world->numViews; ++i) {
+ PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0);
+ }
+
+ for (size_t i = 0; i < world->numViews; ++i) {
+ puglDispatchViewEvents(world->views[i]);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglUpdate(PuglWorld* world, double timeout)
+{
+ const double startTime = puglGetTime(world);
+ PuglStatus st = PUGL_SUCCESS;
+
+ if (timeout < 0.0) {
+ st = puglPollWinEvents(world, timeout);
+ st = st ? st : puglDispatchWinEvents(world);
+ } else if (timeout == 0.0) {
+ st = puglDispatchWinEvents(world);
+ } else {
+ const double endTime = startTime + timeout - 0.001;
+ for (double t = startTime; t < endTime; t = puglGetTime(world)) {
+ if ((st = puglPollWinEvents(world, endTime - t)) ||
+ (st = puglDispatchWinEvents(world))) {
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < world->numViews; ++i) {
+ if (world->views[i]->visible) {
+ puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE);
+ }
+
+ UpdateWindow(world->views[i]->impl->hwnd);
+ }
+
+ return st;
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ return puglUpdate(view->world, 0.0);
+}
+#endif
+
+LRESULT CALLBACK
+wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch (message) {
+ case WM_CREATE:
+ PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
+ return 0;
+ case WM_CLOSE:
+ PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam);
+ return 0;
+ case WM_DESTROY:
+ return 0;
+ default:
+ if (view && hwnd == view->impl->hwnd) {
+ return handleMessage(view, message, wParam, lParam);
+ } else {
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ }
+}
+
+double
+puglGetTime(const PuglWorld* world)
+{
+ LARGE_INTEGER count;
+ QueryPerformanceCounter(&count);
+ return ((double)count.QuadPart / world->impl->timerFrequency -
+ world->startTime);
+}
+
+PuglStatus
+puglPostRedisplay(PuglView* view)
+{
+ InvalidateRect(view->impl->hwnd, NULL, false);
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglPostRedisplayRect(PuglView* view, const PuglRect rect)
+{
+ const RECT r = {(long)floor(rect.x),
+ (long)floor(rect.y),
+ (long)ceil(rect.x + rect.width),
+ (long)ceil(rect.y + rect.height)};
+
+ InvalidateRect(view->impl->hwnd, &r, false);
+
+ return PUGL_SUCCESS;
+}
+
+PuglNativeView
+puglGetNativeWindow(PuglView* view)
+{
+ return (PuglNativeView)view->impl->hwnd;
+}
+
+PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title)
+{
+ puglSetString(&view->title, title);
+
+ if (view->impl->hwnd) {
+ wchar_t* wtitle = puglUtf8ToWideChar(title);
+ if (wtitle) {
+ SetWindowTextW(view->impl->hwnd, wtitle);
+ free(wtitle);
+ }
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetFrame(PuglView* view, const PuglRect frame)
+{
+ view->frame = frame;
+
+ if (view->impl->hwnd) {
+ RECT rect = { (long)frame.x,
+ (long)frame.y,
+ (long)frame.x + (long)frame.width,
+ (long)frame.y + (long)frame.height };
+
+ AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view),
+ FALSE,
+ puglWinGetWindowExFlags(view));
+
+ if (!SetWindowPos(view->impl->hwnd,
+ HWND_TOP,
+ rect.left,
+ rect.top,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) {
+ return PUGL_UNKNOWN_ERROR;
+ }
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetMinSize(PuglView* const view, const int width, const int height)
+{
+ view->minWidth = width;
+ view->minHeight = height;
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetAspectRatio(PuglView* const view,
+ const int minX,
+ const int minY,
+ const int maxX,
+ const int maxY)
+{
+ view->minAspectX = minX;
+ view->minAspectY = minY;
+ view->maxAspectX = maxX;
+ view->maxAspectY = maxY;
+ return PUGL_SUCCESS;
+}
+
+const void*
+puglGetClipboard(PuglView* const view,
+ const char** const type,
+ size_t* const len)
+{
+ PuglInternals* const impl = view->impl;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT) ||
+ !OpenClipboard(impl->hwnd)) {
+ return NULL;
+ }
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL;
+ if (!wstr) {
+ CloseClipboard();
+ return NULL;
+ }
+
+ free(view->clipboard.data);
+ view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len);
+ GlobalUnlock(mem);
+ CloseClipboard();
+
+ return puglGetInternalClipboard(view, type, len);
+}
+
+PuglStatus
+puglSetClipboard(PuglView* const view,
+ const char* const type,
+ const void* const data,
+ const size_t len)
+{
+ PuglInternals* const impl = view->impl;
+
+ PuglStatus st = puglSetInternalClipboard(view, type, data, len);
+ if (st) {
+ return st;
+ } else if (!OpenClipboard(impl->hwnd)) {
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ // Measure string and allocate global memory for clipboard
+ const char* str = (const char*)data;
+ const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wlen + 1) * sizeof(wchar_t));
+ if (!mem) {
+ CloseClipboard();
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ // Lock global memory
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (!wstr) {
+ GlobalFree(mem);
+ CloseClipboard();
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ // Convert string into global memory and set it as clipboard data
+ MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen);
+ wstr[wlen] = 0;
+ GlobalUnlock(mem);
+ SetClipboardData(CF_UNICODETEXT, mem);
+ CloseClipboard();
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinStubEnter(PuglView* view, const PuglEventExpose* expose)
+{
+ if (expose) {
+ PAINTSTRUCT ps;
+ BeginPaint(view->impl->hwnd, &ps);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinStubLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ if (expose) {
+ PAINTSTRUCT ps;
+ EndPaint(view->impl->hwnd, &ps);
+ SwapBuffers(view->impl->hdc);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+const PuglBackend*
+puglStubBackend(void)
+{
+ static const PuglBackend backend = {puglWinStubConfigure,
+ puglStubCreate,
+ puglStubDestroy,
+ puglWinStubEnter,
+ puglWinStubLeave,
+ puglStubGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/win.h b/subprojects/d2tk/pugl/pugl/detail/win.h
new file mode 100644
index 00000000..949fa901
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/win.h
@@ -0,0 +1,141 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 win.h Shared definitions for Windows implementation.
+*/
+
+#include "pugl/detail/implementation.h"
+
+#include <windows.h>
+
+#include <stdbool.h>
+
+typedef PIXELFORMATDESCRIPTOR PuglWinPFD;
+
+struct PuglWorldInternalsImpl {
+ double timerFrequency;
+};
+
+struct PuglInternalsImpl {
+ PuglWinPFD pfd;
+ int pfId;
+ HWND hwnd;
+ HDC hdc;
+ PuglSurface* surface;
+ DWORD refreshRate;
+ bool flashing;
+ bool resizing;
+ bool mouseTracked;
+};
+
+static inline PuglWinPFD
+puglWinGetPixelFormatDescriptor(const PuglHints hints)
+{
+ const int rgbBits = (hints[PUGL_RED_BITS] + //
+ hints[PUGL_GREEN_BITS] + //
+ hints[PUGL_BLUE_BITS]);
+
+ const DWORD dwFlags = hints[PUGL_DOUBLE_BUFFER] ? PFD_DOUBLEBUFFER : 0u;
+
+ PuglWinPFD pfd;
+ ZeroMemory(&pfd, sizeof(pfd));
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | dwFlags;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = (BYTE)rgbBits;
+ pfd.cRedBits = (BYTE)hints[PUGL_RED_BITS];
+ pfd.cGreenBits = (BYTE)hints[PUGL_GREEN_BITS];
+ pfd.cBlueBits = (BYTE)hints[PUGL_BLUE_BITS];
+ pfd.cAlphaBits = (BYTE)hints[PUGL_ALPHA_BITS];
+ pfd.cDepthBits = (BYTE)hints[PUGL_DEPTH_BITS];
+ pfd.cStencilBits = (BYTE)hints[PUGL_STENCIL_BITS];
+ pfd.iLayerType = PFD_MAIN_PLANE;
+ return pfd;
+}
+
+static inline unsigned
+puglWinGetWindowFlags(const PuglView* const view)
+{
+ const bool resizable = view->hints[PUGL_RESIZABLE];
+ const unsigned sizeFlags = resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0u;
+
+ return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
+ (view->parent
+ ? WS_CHILD
+ : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | sizeFlags)));
+}
+
+static inline unsigned
+puglWinGetWindowExFlags(const PuglView* const view)
+{
+ return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW);
+}
+
+static inline PuglStatus
+puglWinCreateWindow(const PuglView* const view,
+ const char* const title,
+ HWND* const hwnd,
+ HDC* const hdc)
+{
+ const char* className = (const char*)view->world->className;
+ const unsigned winFlags = puglWinGetWindowFlags(view);
+ const unsigned winExFlags = puglWinGetWindowExFlags(view);
+
+ // Calculate total window size to accommodate requested view size
+ RECT wr = { (long)view->frame.x, (long)view->frame.y,
+ (long)view->frame.width, (long)view->frame.height };
+ AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags);
+
+ // Create window and get drawing context
+ if (!(*hwnd = CreateWindowEx(winExFlags, className, title, winFlags,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ wr.right-wr.left, wr.bottom-wr.top,
+ (HWND)view->parent, NULL, NULL, NULL))) {
+ return PUGL_REALIZE_FAILED;
+ } else if (!(*hdc = GetDC(*hwnd))) {
+ DestroyWindow(*hwnd);
+ *hwnd = NULL;
+ return PUGL_REALIZE_FAILED;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static inline PuglStatus
+puglWinStubConfigure(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglStatus st = PUGL_SUCCESS;
+
+ if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) {
+ return st;
+ }
+
+ impl->pfd = puglWinGetPixelFormatDescriptor(view->hints);
+ impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd);
+
+ if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) {
+ ReleaseDC(impl->hwnd, impl->hdc);
+ DestroyWindow(impl->hwnd);
+ impl->hwnd = NULL;
+ impl->hdc = NULL;
+ return PUGL_SET_FORMAT_FAILED;
+ }
+
+ return PUGL_SUCCESS;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/win_cairo.c b/subprojects/d2tk/pugl/pugl/detail/win_cairo.c
new file mode 100644
index 00000000..a8b371f1
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/win_cairo.c
@@ -0,0 +1,178 @@
+/*
+ Copyright 2012-2020 David Robillard <http://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 win_cairo.c Cairo graphics backend for Windows.
+*/
+
+#include "pugl/detail/types.h"
+#include "pugl/detail/win.h"
+#include "pugl/pugl_cairo.h"
+#include "pugl/pugl_stub.h"
+
+#include <cairo-win32.h>
+#include <cairo.h>
+
+#include <stdlib.h>
+
+typedef struct {
+ cairo_surface_t* surface;
+ cairo_t* cr;
+ HDC drawDc;
+ HBITMAP drawBitmap;
+} PuglWinCairoSurface;
+
+static PuglStatus
+puglWinCairoCreateDrawContext(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
+
+ surface->drawDc = CreateCompatibleDC(impl->hdc);
+ surface->drawBitmap = CreateCompatibleBitmap(
+ impl->hdc, (int)view->frame.width, (int)view->frame.height);
+
+ DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap));
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinCairoDestroyDrawContext(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
+
+ DeleteDC(surface->drawDc);
+ DeleteObject(surface->drawBitmap);
+
+ surface->drawDc = NULL;
+ surface->drawBitmap = NULL;
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinCairoConfigure(PuglView* view)
+{
+ const PuglStatus st = puglWinStubConfigure(view);
+
+ if (!st) {
+ view->impl->surface = (PuglWinCairoSurface*)calloc(
+ 1, sizeof(PuglWinCairoSurface));
+ }
+
+ return st;
+}
+
+static void
+puglWinCairoClose(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
+
+ cairo_surface_destroy(surface->surface);
+
+ surface->surface = NULL;
+}
+
+static PuglStatus
+puglWinCairoOpen(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
+
+ cairo_status_t st = CAIRO_STATUS_SUCCESS;
+ if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) ||
+ (st = cairo_surface_status(surface->surface)) ||
+ !(surface->cr = cairo_create(surface->surface)) ||
+ (st = cairo_status(surface->cr))) {
+ return PUGL_CREATE_CONTEXT_FAILED;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinCairoDestroy(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
+
+ puglWinCairoClose(view);
+ puglWinCairoDestroyDrawContext(view);
+ free(surface);
+ impl->surface = NULL;
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinCairoEnter(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglStatus st = PUGL_SUCCESS;
+
+ if (expose &&
+ !(st = puglWinCairoCreateDrawContext(view)) &&
+ !(st = puglWinCairoOpen(view))) {
+ PAINTSTRUCT ps;
+ BeginPaint(view->impl->hwnd, &ps);
+ }
+
+ return st;
+}
+
+static PuglStatus
+puglWinCairoLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface;
+
+ if (expose) {
+ cairo_surface_flush(surface->surface);
+ BitBlt(impl->hdc,
+ 0, 0, (int)view->frame.width, (int)view->frame.height,
+ surface->drawDc, 0, 0, SRCCOPY);
+
+ puglWinCairoClose(view);
+ puglWinCairoDestroyDrawContext(view);
+
+ PAINTSTRUCT ps;
+ EndPaint(view->impl->hwnd, &ps);
+ SwapBuffers(view->impl->hdc);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static void*
+puglWinCairoGetContext(PuglView* view)
+{
+ return ((PuglWinCairoSurface*)view->impl->surface)->cr;
+}
+
+const PuglBackend*
+puglCairoBackend()
+{
+ static const PuglBackend backend = {puglWinCairoConfigure,
+ puglStubCreate,
+ puglWinCairoDestroy,
+ puglWinCairoEnter,
+ puglWinCairoLeave,
+ puglWinCairoGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/win_gl.c b/subprojects/d2tk/pugl/pugl/detail/win_gl.c
new file mode 100644
index 00000000..f5acfd62
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/win_gl.c
@@ -0,0 +1,308 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 win_gl.c OpenGL graphics backend for Windows.
+*/
+
+#include "pugl/detail/types.h"
+#include "pugl/detail/win.h"
+#include "pugl/pugl_gl.h"
+#include "pugl/pugl_stub.h"
+
+#include <windows.h>
+
+#include <GL/gl.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define WGL_DRAW_TO_WINDOW_ARB 0x2001
+#define WGL_ACCELERATION_ARB 0x2003
+#define WGL_SUPPORT_OPENGL_ARB 0x2010
+#define WGL_DOUBLE_BUFFER_ARB 0x2011
+#define WGL_PIXEL_TYPE_ARB 0x2013
+#define WGL_COLOR_BITS_ARB 0x2014
+#define WGL_RED_BITS_ARB 0x2015
+#define WGL_GREEN_BITS_ARB 0x2017
+#define WGL_BLUE_BITS_ARB 0x2019
+#define WGL_ALPHA_BITS_ARB 0x201b
+#define WGL_DEPTH_BITS_ARB 0x2022
+#define WGL_STENCIL_BITS_ARB 0x2023
+#define WGL_FULL_ACCELERATION_ARB 0x2027
+#define WGL_TYPE_RGBA_ARB 0x202b
+#define WGL_SAMPLE_BUFFERS_ARB 0x2041
+#define WGL_SAMPLES_ARB 0x2042
+
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
+
+typedef HGLRC (*WglCreateContextAttribs)(HDC, HGLRC, const int*);
+typedef BOOL (*WglSwapInterval)(int);
+typedef BOOL (*WglChoosePixelFormat)(
+ HDC, const int*, const FLOAT*, UINT, int*, UINT*);
+
+typedef struct {
+ WglChoosePixelFormat wglChoosePixelFormat;
+ WglCreateContextAttribs wglCreateContextAttribs;
+ WglSwapInterval wglSwapInterval;
+} PuglWinGlProcs;
+
+typedef struct {
+ PuglWinGlProcs procs;
+ HGLRC hglrc;
+} PuglWinGlSurface;
+
+// Struct to manage the fake window used during configuration
+typedef struct {
+ HWND hwnd;
+ HDC hdc;
+} PuglFakeWindow;
+
+static PuglStatus
+puglWinError(PuglFakeWindow* fakeWin, const PuglStatus status)
+{
+ if (fakeWin->hwnd) {
+ ReleaseDC(fakeWin->hwnd, fakeWin->hdc);
+ DestroyWindow(fakeWin->hwnd);
+ }
+
+ return status;
+}
+
+static PuglWinGlProcs puglWinGlGetProcs(void)
+{
+ const PuglWinGlProcs procs = {
+ (WglChoosePixelFormat)(
+ wglGetProcAddress("wglChoosePixelFormatARB")),
+ (WglCreateContextAttribs)(
+ wglGetProcAddress("wglCreateContextAttribsARB")),
+ (WglSwapInterval)(
+ wglGetProcAddress("wglSwapIntervalEXT"))
+ };
+
+ return procs;
+}
+
+static PuglStatus
+puglWinGlConfigure(PuglView* view)
+{
+ PuglInternals* impl = view->impl;
+
+ // clang-format off
+ const int pixelAttrs[] = {
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
+ WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
+ WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER],
+ WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
+ WGL_SAMPLE_BUFFERS_ARB, view->hints[PUGL_SAMPLES] ? 1 : 0,
+ WGL_SAMPLES_ARB, view->hints[PUGL_SAMPLES],
+ WGL_RED_BITS_ARB, view->hints[PUGL_RED_BITS],
+ WGL_GREEN_BITS_ARB, view->hints[PUGL_GREEN_BITS],
+ WGL_BLUE_BITS_ARB, view->hints[PUGL_BLUE_BITS],
+ WGL_ALPHA_BITS_ARB, view->hints[PUGL_ALPHA_BITS],
+ WGL_DEPTH_BITS_ARB, view->hints[PUGL_DEPTH_BITS],
+ WGL_STENCIL_BITS_ARB, view->hints[PUGL_STENCIL_BITS],
+ 0,
+ };
+ // clang-format on
+
+ PuglWinGlSurface* const surface =
+ (PuglWinGlSurface*)calloc(1, sizeof(PuglWinGlSurface));
+ impl->surface = surface;
+
+ // Create fake window for getting at GL context
+ PuglStatus st = PUGL_SUCCESS;
+ PuglFakeWindow fakeWin = {0, 0};
+ static const char* title = "Pugl Configuration";
+ if ((st = puglWinCreateWindow(view, title, &fakeWin.hwnd, &fakeWin.hdc))) {
+ return puglWinError(&fakeWin, st);
+ }
+
+ // Set pixel format for fake window
+ const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints);
+ const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd);
+ if (!fakePfId) {
+ return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
+ } else if (!SetPixelFormat(fakeWin.hdc, fakePfId, &fakePfd)) {
+ return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
+ }
+
+ // Create fake GL context to get at the functions we need
+ HGLRC fakeRc = wglCreateContext(fakeWin.hdc);
+ if (!fakeRc) {
+ return puglWinError(&fakeWin, PUGL_CREATE_CONTEXT_FAILED);
+ }
+
+ // Enter fake context and get extension functions
+ wglMakeCurrent(fakeWin.hdc, fakeRc);
+ surface->procs = puglWinGlGetProcs();
+
+ if (surface->procs.wglChoosePixelFormat) {
+ // Choose pixel format based on attributes
+ UINT numFormats = 0;
+ if (!surface->procs.wglChoosePixelFormat(
+ fakeWin.hdc, pixelAttrs, NULL, 1u, &impl->pfId, &numFormats)) {
+ return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED);
+ }
+
+ DescribePixelFormat(
+ impl->hdc, impl->pfId, sizeof(impl->pfd), &impl->pfd);
+ } else {
+ // Modern extensions not available, use basic pixel format
+ impl->pfd = fakePfd;
+ impl->pfId = fakePfId;
+ }
+
+ // Dispose of fake window and context
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(fakeRc);
+ ReleaseDC(fakeWin.hwnd, fakeWin.hdc);
+ DestroyWindow(fakeWin.hwnd);
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinGlCreate(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWinGlSurface* const surface = (PuglWinGlSurface*)impl->surface;
+ PuglStatus st = PUGL_SUCCESS;
+
+ const int contextAttribs[] = {
+ WGL_CONTEXT_MAJOR_VERSION_ARB,
+ view->hints[PUGL_CONTEXT_VERSION_MAJOR],
+
+ WGL_CONTEXT_MINOR_VERSION_ARB,
+ view->hints[PUGL_CONTEXT_VERSION_MINOR],
+
+ WGL_CONTEXT_FLAGS_ARB,
+ (view->hints[PUGL_USE_DEBUG_CONTEXT] ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+
+ WGL_CONTEXT_PROFILE_MASK_ARB,
+ (view->hints[PUGL_USE_COMPAT_PROFILE]
+ ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB
+ : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB),
+
+ 0};
+
+ // Create real window with desired pixel format
+ if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) {
+ return st;
+ } else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) {
+ ReleaseDC(impl->hwnd, impl->hdc);
+ DestroyWindow(impl->hwnd);
+ impl->hwnd = NULL;
+ impl->hdc = NULL;
+ return PUGL_SET_FORMAT_FAILED;
+ }
+
+ // Create GL context
+ if (surface->procs.wglCreateContextAttribs &&
+ !(surface->hglrc = surface->procs.wglCreateContextAttribs(
+ impl->hdc, 0, contextAttribs))) {
+ return PUGL_CREATE_CONTEXT_FAILED;
+ } else if (!(surface->hglrc = wglCreateContext(impl->hdc))) {
+ return PUGL_CREATE_CONTEXT_FAILED;
+ }
+
+ // Enter context and set swap interval
+ wglMakeCurrent(impl->hdc, surface->hglrc);
+ const int swapInterval = view->hints[PUGL_SWAP_INTERVAL];
+ if (surface->procs.wglSwapInterval && swapInterval != PUGL_DONT_CARE) {
+ surface->procs.wglSwapInterval(swapInterval);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinGlDestroy(PuglView* view)
+{
+ PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface;
+ if (surface) {
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(surface->hglrc);
+ free(surface);
+ view->impl->surface = NULL;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinGlEnter(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface;
+
+ wglMakeCurrent(view->impl->hdc, surface->hglrc);
+
+ if (expose) {
+ PAINTSTRUCT ps;
+ BeginPaint(view->impl->hwnd, &ps);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglWinGlLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ if (expose) {
+ PAINTSTRUCT ps;
+ EndPaint(view->impl->hwnd, &ps);
+ SwapBuffers(view->impl->hdc);
+ }
+
+ wglMakeCurrent(NULL, NULL);
+ return PUGL_SUCCESS;
+}
+
+PuglGlFunc
+puglGetProcAddress(const char* name)
+{
+ const PuglGlFunc func = (PuglGlFunc)wglGetProcAddress(name);
+
+ /* Windows has the annoying property that wglGetProcAddress returns NULL
+ for functions from OpenGL 1.1, so we fall back to pulling them directly
+ from opengl32.dll */
+
+ return func
+ ? func
+ : (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name);
+}
+
+const PuglBackend*
+puglGlBackend()
+{
+ static const PuglBackend backend = {puglWinGlConfigure,
+ puglWinGlCreate,
+ puglWinGlDestroy,
+ puglWinGlEnter,
+ puglWinGlLeave,
+ puglStubGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/x11.c b/subprojects/d2tk/pugl/pugl/detail/x11.c
new file mode 100644
index 00000000..e3fb2649
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/x11.c
@@ -0,0 +1,1218 @@
+/*
+ Copyright 2012-2020 David Robillard <http://drobilla.net>
+ Copyright 2013 Robin Gareus <robin@gareus.org>
+ Copyright 2011-2012 Ben Loftis, Harrison Consoles
+
+ 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 x11.c X11 implementation.
+*/
+
+#define _POSIX_C_SOURCE 199309L
+
+#include "pugl/detail/x11.h"
+
+#include "pugl/detail/implementation.h"
+#include "pugl/detail/types.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_stub.h"
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#ifdef HAVE_XSYNC
+# include <X11/extensions/sync.h>
+# include <X11/extensions/syncconst.h>
+#endif
+
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+# define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+enum WmClientStateMessageAction {
+ WM_STATE_REMOVE,
+ WM_STATE_ADD,
+ WM_STATE_TOGGLE
+};
+
+static const long eventMask =
+ (ExposureMask | StructureNotifyMask |
+ VisibilityChangeMask | FocusChangeMask |
+ EnterWindowMask | LeaveWindowMask | PointerMotionMask |
+ ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask);
+
+static bool
+puglInitXSync(PuglWorldInternals* impl)
+{
+#ifdef HAVE_XSYNC
+ int syncMajor;
+ int syncMinor;
+ int errorBase;
+ XSyncSystemCounter* counters;
+ int numCounters;
+
+ if (XSyncQueryExtension(impl->display, &impl->syncEventBase, &errorBase) &&
+ XSyncInitialize(impl->display, &syncMajor, &syncMinor) &&
+ (counters = XSyncListSystemCounters(impl->display, &numCounters))) {
+
+ for (int n = 0; n < numCounters; ++n) {
+ if (!strcmp(counters[n].name, "SERVERTIME")) {
+ impl->serverTimeCounter = counters[n].counter;
+ impl->syncSupported = true;
+ break;
+ }
+ }
+
+ XSyncFreeSystemCounterList(counters);
+ }
+#else
+ (void)impl;
+#endif
+
+ return false;
+}
+
+PuglWorldInternals*
+puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags)
+{
+ if (type == PUGL_PROGRAM && (flags & PUGL_WORLD_THREADS)) {
+ XInitThreads();
+ }
+
+ Display* display = XOpenDisplay(NULL);
+ if (!display) {
+ return NULL;
+ }
+
+ PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
+ 1, sizeof(PuglWorldInternals));
+
+ impl->display = display;
+
+ // Intern the various atoms we will need
+ impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0);
+ impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0);
+ impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0);
+ impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0);
+ impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0);
+ impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0);
+ impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0);
+ impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION =
+ XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 0);
+
+ // Open input method
+ XSetLocaleModifiers("");
+ if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) {
+ XSetLocaleModifiers("@im=");
+ impl->xim = XOpenIM(display, NULL, NULL, NULL);
+ }
+
+ puglInitXSync(impl);
+ XFlush(display);
+
+ return impl;
+}
+
+void*
+puglGetNativeWorld(PuglWorld* world)
+{
+ return world->impl->display;
+}
+
+PuglInternals*
+puglInitViewInternals(void)
+{
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
+}
+
+static PuglStatus
+puglPollX11Socket(PuglWorld* world, const double timeout)
+{
+ if (XPending(world->impl->display) > 0) {
+ return PUGL_SUCCESS;
+ }
+
+ const int fd = ConnectionNumber(world->impl->display);
+ const int nfds = fd + 1;
+ int ret = 0;
+ fd_set fds;
+ FD_ZERO(&fds); // NOLINT
+ FD_SET(fd, &fds);
+
+ if (timeout < 0.0) {
+ ret = select(nfds, &fds, NULL, NULL, NULL);
+ } else {
+ const long sec = (long)timeout;
+ const long usec = (long)((timeout - (double)sec) * 1e6);
+ struct timeval tv = {sec, usec};
+ ret = select(nfds, &fds, NULL, NULL, &tv);
+ }
+
+ return ret < 0 ? PUGL_UNKNOWN_ERROR : PUGL_SUCCESS;
+}
+
+static PuglView*
+puglFindView(PuglWorld* world, const Window window)
+{
+ for (size_t i = 0; i < world->numViews; ++i) {
+ if (world->views[i]->impl->win == window) {
+ return world->views[i];
+ }
+ }
+
+ return NULL;
+}
+
+static XSizeHints
+getSizeHints(const PuglView* view)
+{
+ XSizeHints sizeHints = {0};
+
+ if (!view->hints[PUGL_RESIZABLE]) {
+ sizeHints.flags = PMinSize|PMaxSize;
+ sizeHints.min_width = (int)view->frame.width;
+ sizeHints.min_height = (int)view->frame.height;
+ sizeHints.max_width = (int)view->frame.width;
+ sizeHints.max_height = (int)view->frame.height;
+ } else {
+ if (view->minWidth || view->minHeight) {
+ sizeHints.flags = PMinSize;
+ sizeHints.min_width = view->minWidth;
+ sizeHints.min_height = view->minHeight;
+ }
+ if (view->minAspectX) {
+ sizeHints.flags |= PAspect;
+ sizeHints.min_aspect.x = view->minAspectX;
+ sizeHints.min_aspect.y = view->minAspectY;
+ sizeHints.max_aspect.x = view->maxAspectX;
+ sizeHints.max_aspect.y = view->maxAspectY;
+ }
+ }
+
+ return sizeHints;
+}
+
+PuglStatus
+puglRealize(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWorld* const world = view->world;
+ PuglX11Atoms* const atoms = &view->world->impl->atoms;
+ Display* const display = world->impl->display;
+
+ impl->display = display;
+ impl->screen = DefaultScreen(display);
+
+ if (!view->backend || !view->backend->configure) {
+ return PUGL_BAD_BACKEND;
+ }
+
+ PuglStatus st = view->backend->configure(view);
+ if (st || !impl->vi) {
+ view->backend->destroy(view);
+ return st ? st : PUGL_BACKEND_FAILED;
+ }
+
+ Window xParent = view->parent ? (Window)view->parent
+ : RootWindow(display, impl->screen);
+
+ Colormap cmap = XCreateColormap(
+ display, xParent, impl->vi->visual, AllocNone);
+
+ XSetWindowAttributes attr = {0};
+ attr.colormap = cmap;
+ attr.event_mask = eventMask;
+
+ const Window win = impl->win = XCreateWindow(
+ display, xParent,
+ (int)view->frame.x, (int)view->frame.y,
+ (unsigned)view->frame.width, (unsigned)view->frame.height,
+ 0, impl->vi->depth, InputOutput,
+ impl->vi->visual, CWColormap | CWEventMask, &attr);
+
+ if ((st = view->backend->create(view))) {
+ return st;
+ }
+
+ XSizeHints sizeHints = getSizeHints(view);
+ XSetNormalHints(display, win, &sizeHints);
+
+ XClassHint classHint = { world->className, world->className };
+ XSetClassHint(display, win, &classHint);
+
+ if (view->title) {
+ puglSetWindowTitle(view, view->title);
+ }
+
+ if (!view->parent) {
+ XSetWMProtocols(display, win, &atoms->WM_DELETE_WINDOW, 1);
+ }
+
+ if (view->transientParent) {
+ XSetTransientForHint(display, win, (Window)(view->transientParent));
+ }
+
+ // Create input context
+ const XIMStyle im_style = XIMPreeditNothing | XIMStatusNothing;
+ if (!(impl->xic = XCreateIC(world->impl->xim,
+ XNInputStyle, im_style,
+ XNClientWindow, win,
+ XNFocusWindow, win,
+ NULL))) {
+ view->world->logFunc(view->world,
+ PUGL_LOG_LEVEL_WARNING,
+ "XCreateID failed\n");
+ }
+
+ puglDispatchSimpleEvent(view, PUGL_CREATE);
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglShowWindow(PuglView* view)
+{
+ PuglStatus st = PUGL_SUCCESS;
+
+ if (!view->impl->win) {
+ if ((st = puglRealize(view))) {
+ return st;
+ }
+ }
+
+ XMapRaised(view->impl->display, view->impl->win);
+ puglPostRedisplay(view);
+
+ return st;
+}
+
+PuglStatus
+puglHideWindow(PuglView* view)
+{
+ XUnmapWindow(view->impl->display, view->impl->win);
+ return PUGL_SUCCESS;
+}
+
+void
+puglFreeViewInternals(PuglView* view)
+{
+ if (view && view->impl) {
+ if (view->impl->xic) {
+ XDestroyIC(view->impl->xic);
+ }
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+ if (view->impl->display) {
+ XDestroyWindow(view->impl->display, view->impl->win);
+ }
+ XFree(view->impl->vi);
+ free(view->impl);
+ }
+}
+
+void
+puglFreeWorldInternals(PuglWorld* world)
+{
+ if (world->impl->xim) {
+ XCloseIM(world->impl->xim);
+ }
+ XCloseDisplay(world->impl->display);
+ free(world->impl->timers);
+ free(world->impl);
+}
+
+static PuglKey
+keySymToSpecial(KeySym sym)
+{
+ switch (sym) {
+ case XK_F1: return PUGL_KEY_F1;
+ case XK_F2: return PUGL_KEY_F2;
+ case XK_F3: return PUGL_KEY_F3;
+ case XK_F4: return PUGL_KEY_F4;
+ case XK_F5: return PUGL_KEY_F5;
+ case XK_F6: return PUGL_KEY_F6;
+ case XK_F7: return PUGL_KEY_F7;
+ case XK_F8: return PUGL_KEY_F8;
+ case XK_F9: return PUGL_KEY_F9;
+ case XK_F10: return PUGL_KEY_F10;
+ case XK_F11: return PUGL_KEY_F11;
+ case XK_F12: return PUGL_KEY_F12;
+ case XK_Left: return PUGL_KEY_LEFT;
+ case XK_Up: return PUGL_KEY_UP;
+ case XK_Right: return PUGL_KEY_RIGHT;
+ case XK_Down: return PUGL_KEY_DOWN;
+ case XK_Page_Up: return PUGL_KEY_PAGE_UP;
+ case XK_Page_Down: return PUGL_KEY_PAGE_DOWN;
+ case XK_Home: return PUGL_KEY_HOME;
+ case XK_End: return PUGL_KEY_END;
+ case XK_Insert: return PUGL_KEY_INSERT;
+ case XK_Shift_L: return PUGL_KEY_SHIFT_L;
+ case XK_Shift_R: return PUGL_KEY_SHIFT_R;
+ case XK_Control_L: return PUGL_KEY_CTRL_L;
+ case XK_Control_R: return PUGL_KEY_CTRL_R;
+ case XK_Alt_L: return PUGL_KEY_ALT_L;
+ case XK_ISO_Level3_Shift:
+ case XK_Alt_R: return PUGL_KEY_ALT_R;
+ case XK_Super_L: return PUGL_KEY_SUPER_L;
+ case XK_Super_R: return PUGL_KEY_SUPER_R;
+ case XK_Menu: return PUGL_KEY_MENU;
+ case XK_Caps_Lock: return PUGL_KEY_CAPS_LOCK;
+ case XK_Scroll_Lock: return PUGL_KEY_SCROLL_LOCK;
+ case XK_Num_Lock: return PUGL_KEY_NUM_LOCK;
+ case XK_Print: return PUGL_KEY_PRINT_SCREEN;
+ case XK_Pause: return PUGL_KEY_PAUSE;
+ default: break;
+ }
+ return (PuglKey)0;
+}
+
+static int
+lookupString(XIC xic, XEvent* xevent, char* str, KeySym* sym)
+{
+ Status status = 0;
+
+#ifdef X_HAVE_UTF8_STRING
+ const int n = Xutf8LookupString(xic, &xevent->xkey, str, 7, sym, &status);
+#else
+ const int n = XmbLookupString(xic, &xevent->xkey, str, 7, sym, &status);
+#endif
+
+ return status == XBufferOverflow ? 0 : n;
+}
+
+static void
+translateKey(PuglView* view, XEvent* xevent, PuglEvent* event)
+{
+ const unsigned state = xevent->xkey.state;
+ const bool filter = XFilterEvent(xevent, None);
+
+ event->key.keycode = xevent->xkey.keycode;
+ xevent->xkey.state = 0;
+
+ // Lookup unshifted key
+ char ustr[8] = {0};
+ KeySym sym = 0;
+ const int ufound = XLookupString(&xevent->xkey, ustr, 8, &sym, NULL);
+ const PuglKey special = keySymToSpecial(sym);
+
+ event->key.key = ((special || ufound <= 0)
+ ? special
+ : puglDecodeUTF8((const uint8_t*)ustr));
+
+ if (xevent->type == KeyPress && !filter && !special) {
+ // Lookup shifted key for possible text event
+ xevent->xkey.state = state;
+
+ char sstr[8] = {0};
+ const int sfound = lookupString(view->impl->xic, xevent, sstr, &sym);
+ if (sfound > 0) {
+ // Dispatch key event now
+ puglDispatchEvent(view, event);
+
+ // "Return" a text event in its place
+ event->text.type = PUGL_TEXT;
+ event->text.character = puglDecodeUTF8((const uint8_t*)sstr);
+ memcpy(event->text.string, sstr, sizeof(sstr));
+ }
+ }
+}
+
+static uint32_t
+translateModifiers(const unsigned xstate)
+{
+ return (((xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0) |
+ ((xstate & ControlMask) ? PUGL_MOD_CTRL : 0) |
+ ((xstate & Mod1Mask) ? PUGL_MOD_ALT : 0) |
+ ((xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0));
+}
+
+static PuglEvent
+translateEvent(PuglView* view, XEvent xevent)
+{
+ const PuglX11Atoms* atoms = &view->world->impl->atoms;
+
+ PuglEvent event = {{PUGL_NOTHING, 0}};
+ event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0;
+
+ switch (xevent.type) {
+ case ClientMessage:
+ if (xevent.xclient.message_type == atoms->WM_PROTOCOLS) {
+ const Atom protocol = (Atom)xevent.xclient.data.l[0];
+ if (protocol == atoms->WM_DELETE_WINDOW) {
+ event.type = PUGL_CLOSE;
+ }
+ } else if (xevent.xclient.message_type == atoms->PUGL_CLIENT_MSG) {
+ event.type = PUGL_CLIENT;
+ event.client.data1 = (uintptr_t)xevent.xclient.data.l[0];
+ event.client.data2 = (uintptr_t)xevent.xclient.data.l[1];
+ }
+ break;
+ case VisibilityNotify:
+ view->visible = xevent.xvisibility.state != VisibilityFullyObscured;
+ break;
+ case MapNotify:
+ event.type = PUGL_MAP;
+ break;
+ case UnmapNotify:
+ event.type = PUGL_UNMAP;
+ view->visible = false;
+ break;
+ case ConfigureNotify:
+ event.type = PUGL_CONFIGURE;
+ event.configure.x = xevent.xconfigure.x;
+ event.configure.y = xevent.xconfigure.y;
+ event.configure.width = xevent.xconfigure.width;
+ event.configure.height = xevent.xconfigure.height;
+ break;
+ case Expose:
+ event.type = PUGL_EXPOSE;
+ event.expose.x = xevent.xexpose.x;
+ event.expose.y = xevent.xexpose.y;
+ event.expose.width = xevent.xexpose.width;
+ event.expose.height = xevent.xexpose.height;
+ event.expose.count = xevent.xexpose.count;
+ break;
+ case MotionNotify:
+ event.type = PUGL_MOTION;
+ event.motion.time = xevent.xmotion.time / 1e3;
+ event.motion.x = xevent.xmotion.x;
+ event.motion.y = xevent.xmotion.y;
+ event.motion.xRoot = xevent.xmotion.x_root;
+ event.motion.yRoot = xevent.xmotion.y_root;
+ event.motion.state = translateModifiers(xevent.xmotion.state);
+ event.motion.isHint = (xevent.xmotion.is_hint == NotifyHint);
+ break;
+ case ButtonPress:
+ if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) {
+ event.type = PUGL_SCROLL;
+ event.scroll.time = xevent.xbutton.time / 1e3;
+ event.scroll.x = xevent.xbutton.x;
+ event.scroll.y = xevent.xbutton.y;
+ event.scroll.xRoot = xevent.xbutton.x_root;
+ event.scroll.yRoot = xevent.xbutton.y_root;
+ event.scroll.state = translateModifiers(xevent.xbutton.state);
+ event.scroll.dx = 0.0;
+ event.scroll.dy = 0.0;
+ switch (xevent.xbutton.button) {
+ case 4: event.scroll.dy = 1.0; break;
+ case 5: event.scroll.dy = -1.0; break;
+ case 6: event.scroll.dx = -1.0; break;
+ case 7: event.scroll.dx = 1.0; break;
+ }
+ // fallthru
+ }
+ // fallthru
+ case ButtonRelease:
+ if (xevent.xbutton.button < 4 || xevent.xbutton.button > 7) {
+ event.button.type = ((xevent.type == ButtonPress)
+ ? PUGL_BUTTON_PRESS
+ : PUGL_BUTTON_RELEASE);
+ event.button.time = xevent.xbutton.time / 1e3;
+ event.button.x = xevent.xbutton.x;
+ event.button.y = xevent.xbutton.y;
+ event.button.xRoot = xevent.xbutton.x_root;
+ event.button.yRoot = xevent.xbutton.y_root;
+ event.button.state = translateModifiers(xevent.xbutton.state);
+ event.button.button = xevent.xbutton.button;
+ }
+ break;
+ case KeyPress:
+ case KeyRelease:
+ event.type = ((xevent.type == KeyPress)
+ ? PUGL_KEY_PRESS
+ : PUGL_KEY_RELEASE);
+ event.key.time = xevent.xkey.time / 1e3;
+ event.key.x = xevent.xkey.x;
+ event.key.y = xevent.xkey.y;
+ event.key.xRoot = xevent.xkey.x_root;
+ event.key.yRoot = xevent.xkey.y_root;
+ event.key.state = translateModifiers(xevent.xkey.state);
+ translateKey(view, &xevent, &event);
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ event.type = ((xevent.type == EnterNotify)
+ ? PUGL_POINTER_IN
+ : PUGL_POINTER_OUT);
+ event.crossing.time = xevent.xcrossing.time / 1e3;
+ event.crossing.x = xevent.xcrossing.x;
+ event.crossing.y = xevent.xcrossing.y;
+ event.crossing.xRoot = xevent.xcrossing.x_root;
+ event.crossing.yRoot = xevent.xcrossing.y_root;
+ event.crossing.state = translateModifiers(xevent.xcrossing.state);
+ event.crossing.mode = PUGL_CROSSING_NORMAL;
+ if (xevent.xcrossing.mode == NotifyGrab) {
+ event.crossing.mode = PUGL_CROSSING_GRAB;
+ } else if (xevent.xcrossing.mode == NotifyUngrab) {
+ event.crossing.mode = PUGL_CROSSING_UNGRAB;
+ }
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ event.type = (xevent.type == FocusIn) ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT;
+ event.focus.grab = (xevent.xfocus.mode != NotifyNormal);
+ break;
+
+ default:
+ break;
+ }
+
+ return event;
+}
+
+PuglStatus
+puglGrabFocus(PuglView* view)
+{
+ XSetInputFocus(
+ view->impl->display, view->impl->win, RevertToNone, CurrentTime);
+ return PUGL_SUCCESS;
+}
+
+bool
+puglHasFocus(const PuglView* view)
+{
+ int revertTo = 0;
+ Window focusedWindow = 0;
+ XGetInputFocus(view->impl->display, &focusedWindow, &revertTo);
+ return focusedWindow == view->impl->win;
+}
+
+PuglStatus
+puglRequestAttention(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ const PuglX11Atoms* const atoms = &view->world->impl->atoms;
+ XEvent event = {0};
+
+ event.type = ClientMessage;
+ event.xclient.window = impl->win;
+ event.xclient.format = 32;
+ event.xclient.message_type = atoms->NET_WM_STATE;
+ event.xclient.data.l[0] = WM_STATE_ADD;
+ event.xclient.data.l[1] = (long)atoms->NET_WM_STATE_DEMANDS_ATTENTION;
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 1;
+ event.xclient.data.l[4] = 0;
+
+ const Window root = RootWindow(impl->display, impl->screen);
+ XSendEvent(impl->display,
+ root,
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &event);
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglStartTimer(PuglView* view, uintptr_t id, double timeout)
+{
+#ifdef HAVE_XSYNC
+ if (view->world->impl->syncSupported) {
+ XSyncValue value;
+ XSyncIntToValue(&value, (int)floor(timeout * 1000.0));
+
+ PuglWorldInternals* w = view->world->impl;
+ Display* const display = w->display;
+ const XSyncCounter counter = w->serverTimeCounter;
+ const XSyncTrigger trigger = {counter, XSyncRelative, value, 0};
+ XSyncAlarmAttributes attr = {trigger, value, True, XSyncAlarmActive};
+ const XSyncAlarm alarm = XSyncCreateAlarm(display, 0x17, &attr);
+ const PuglTimer timer = {alarm, view, id};
+
+ if (alarm != None) {
+ for (size_t i = 0; i < w->numTimers; ++i) {
+ if (w->timers[i].view == view && w->timers[i].id == id) {
+ // Replace existing timer
+ XSyncDestroyAlarm(w->display, w->timers[i].alarm);
+ w->timers[i] = timer;
+ return PUGL_SUCCESS;
+ }
+ }
+
+ // Add new timer
+ const size_t size = ++w->numTimers * sizeof(timer);
+ w->timers = (PuglTimer*)realloc(w->timers, size);
+ w->timers[w->numTimers - 1] = timer;
+ return PUGL_SUCCESS;
+ }
+ }
+#else
+ (void)view;
+ (void)id;
+ (void)timeout;
+#endif
+
+ return PUGL_FAILURE;
+}
+
+PuglStatus
+puglStopTimer(PuglView* view, uintptr_t id)
+{
+#ifdef HAVE_XSYNC
+ PuglWorldInternals* w = view->world->impl;
+
+ for (size_t i = 0; i < w->numTimers; ++i) {
+ if (w->timers[i].view == view && w->timers[i].id == id) {
+ XSyncDestroyAlarm(w->display, w->timers[i].alarm);
+
+ if (i == w->numTimers - 1) {
+ memset(&w->timers[i], 0, sizeof(PuglTimer));
+ } else {
+ memmove(w->timers + i,
+ w->timers + i + 1,
+ sizeof(PuglTimer) * (w->numTimers - i - 1));
+
+ memset(&w->timers[i], 0, sizeof(PuglTimer));
+ }
+
+ --w->numTimers;
+ return PUGL_SUCCESS;
+ }
+ }
+#else
+ (void)view;
+ (void)id;
+#endif
+
+ return PUGL_FAILURE;
+}
+
+static XEvent
+puglEventToX(PuglView* view, const PuglEvent* event)
+{
+ XEvent xev = {0};
+ xev.xany.send_event = True;
+
+ switch (event->type) {
+ case PUGL_EXPOSE: {
+ const double x = floor(event->expose.x);
+ const double y = floor(event->expose.y);
+ const double w = ceil(event->expose.x + event->expose.width) - x;
+ const double h = ceil(event->expose.y + event->expose.height) - y;
+
+ xev.xexpose.type = Expose;
+ xev.xexpose.serial = 0;
+ xev.xexpose.display = view->impl->display;
+ xev.xexpose.window = view->impl->win;
+ xev.xexpose.x = (int)x;
+ xev.xexpose.y = (int)y;
+ xev.xexpose.width = (int)w;
+ xev.xexpose.height = (int)h;
+ break;
+ }
+
+ case PUGL_CLIENT:
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = view->impl->display;
+ xev.xclient.window = view->impl->win;
+ xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = (long)event->client.data1;
+ xev.xclient.data.l[1] = (long)event->client.data2;
+ break;
+
+ default:
+ break;
+ }
+
+ return xev;
+}
+
+PuglStatus
+puglSendEvent(PuglView* view, const PuglEvent* event)
+{
+ XEvent xev = puglEventToX(view, event);
+
+ if (xev.type) {
+ if (XSendEvent(view->impl->display, view->impl->win, False, 0, &xev)) {
+ return PUGL_SUCCESS;
+ }
+ }
+
+ return PUGL_UNSUPPORTED_TYPE;
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+PuglStatus
+puglWaitForEvent(PuglView* view)
+{
+ XEvent xevent;
+ XPeekEvent(view->impl->display, &xevent);
+ return PUGL_SUCCESS;
+}
+#endif
+
+static void
+mergeExposeEvents(PuglEvent* dst, const PuglEvent* src)
+{
+ if (!dst->type) {
+ *dst = *src;
+ } else {
+ const double max_x = MAX(dst->expose.x + dst->expose.width,
+ src->expose.x + src->expose.width);
+ const double max_y = MAX(dst->expose.y + dst->expose.height,
+ src->expose.y + src->expose.height);
+
+ dst->expose.x = MIN(dst->expose.x, src->expose.x);
+ dst->expose.y = MIN(dst->expose.y, src->expose.y);
+ dst->expose.width = max_x - dst->expose.x;
+ dst->expose.height = max_y - dst->expose.y;
+ dst->expose.count = MIN(dst->expose.count, src->expose.count);
+ }
+}
+
+static void
+handleSelectionNotify(const PuglWorld* world, PuglView* view)
+{
+ uint8_t* str = NULL;
+ Atom type = 0;
+ int fmt = 0;
+ unsigned long len = 0;
+ unsigned long left = 0;
+
+ XGetWindowProperty(world->impl->display,
+ view->impl->win,
+ XA_PRIMARY,
+ 0,
+ 0x1FFFFFFF,
+ False,
+ AnyPropertyType,
+ &type,
+ &fmt,
+ &len,
+ &left,
+ &str);
+
+ if (str && fmt == 8 && type == world->impl->atoms.UTF8_STRING &&
+ left == 0) {
+ puglSetBlob(&view->clipboard, str, len);
+ }
+
+ XFree(str);
+}
+
+static void
+handleSelectionRequest(const PuglWorld* world,
+ PuglView* view,
+ const XSelectionRequestEvent* request)
+{
+ XSelectionEvent note = {SelectionNotify,
+ request->serial,
+ False,
+ world->impl->display,
+ request->requestor,
+ request->selection,
+ request->target,
+ None,
+ request->time};
+
+ const char* type = NULL;
+ size_t len = 0;
+ const void* data = puglGetInternalClipboard(view, &type, &len);
+ if (data && request->selection == world->impl->atoms.CLIPBOARD &&
+ request->target == world->impl->atoms.UTF8_STRING) {
+ note.property = request->property;
+ XChangeProperty(world->impl->display,
+ note.requestor,
+ note.property,
+ note.target,
+ 8,
+ PropModeReplace,
+ (const uint8_t*)data,
+ (int)len);
+ } else {
+ note.property = None;
+ }
+
+ XSendEvent(world->impl->display, note.requestor, True, 0, (XEvent*)&note);
+}
+
+/// Flush pending configure and expose events for all views
+static void
+flushExposures(PuglWorld* world)
+{
+ for (size_t i = 0; i < world->numViews; ++i) {
+ PuglView* const view = world->views[i];
+
+ if (view->visible) {
+ puglDispatchSimpleEvent(view, PUGL_UPDATE);
+ }
+
+ const PuglEvent configure = view->impl->pendingConfigure;
+ const PuglEvent expose = view->impl->pendingExpose;
+
+ view->impl->pendingConfigure.type = PUGL_NOTHING;
+ view->impl->pendingExpose.type = PUGL_NOTHING;
+
+ if (configure.type || expose.type) {
+ view->backend->enter(view, expose.type ? &expose.expose : NULL);
+ puglDispatchEventInContext(view, &configure);
+ puglDispatchEventInContext(view, &expose);
+ view->backend->leave(view, expose.type ? &expose.expose : NULL);
+ }
+ }
+}
+
+static bool
+handleTimerEvent(PuglWorld* world, XEvent xevent)
+{
+#ifdef HAVE_XSYNC
+ if (xevent.type == world->impl->syncEventBase + XSyncAlarmNotify) {
+ XSyncAlarmNotifyEvent* notify = ((XSyncAlarmNotifyEvent*)&xevent);
+
+ for (size_t i = 0; i < world->impl->numTimers; ++i) {
+ if (world->impl->timers[i].alarm == notify->alarm) {
+ const PuglEventTimer ev = {PUGL_TIMER, 0, world->impl->timers[i].id};
+ puglDispatchEvent(world->impl->timers[i].view, (const PuglEvent*)&ev);
+ }
+ }
+
+ return true;
+ }
+#else
+ (void)world;
+ (void)xevent;
+#endif
+
+ return false;
+}
+
+static PuglStatus
+puglDispatchX11Events(PuglWorld* world)
+{
+ const PuglX11Atoms* const atoms = &world->impl->atoms;
+
+ // Flush output to the server once at the start
+ Display* display = world->impl->display;
+ XFlush(display);
+
+ // Process all queued events (without further flushing)
+ while (XEventsQueued(display, QueuedAfterReading) > 0) {
+ XEvent xevent;
+ XNextEvent(display, &xevent);
+
+ if (handleTimerEvent(world, xevent)) {
+ continue;
+ }
+
+ PuglView* view = puglFindView(world, xevent.xany.window);
+ if (!view) {
+ continue;
+ }
+
+ // Handle special events
+ PuglInternals* const impl = view->impl;
+ if (xevent.type == KeyRelease && view->hints[PUGL_IGNORE_KEY_REPEAT]) {
+ XEvent next;
+ if (XCheckTypedWindowEvent(display, impl->win, KeyPress, &next) &&
+ next.type == KeyPress &&
+ next.xkey.time == xevent.xkey.time &&
+ next.xkey.keycode == xevent.xkey.keycode) {
+ continue;
+ }
+ } else if (xevent.type == FocusIn) {
+ XSetICFocus(impl->xic);
+ } else if (xevent.type == FocusOut) {
+ XUnsetICFocus(impl->xic);
+ } else if (xevent.type == SelectionClear) {
+ puglSetBlob(&view->clipboard, NULL, 0);
+ } else if (xevent.type == SelectionNotify &&
+ xevent.xselection.selection == atoms->CLIPBOARD &&
+ xevent.xselection.target == atoms->UTF8_STRING &&
+ xevent.xselection.property == XA_PRIMARY) {
+ handleSelectionNotify(world, view);
+ } else if (xevent.type == SelectionRequest) {
+ handleSelectionRequest(world, view, &xevent.xselectionrequest);
+ }
+
+ // Translate X11 event to Pugl event
+ const PuglEvent event = translateEvent(view, xevent);
+
+ if (event.type == PUGL_EXPOSE) {
+ // Expand expose event to be dispatched after loop
+ mergeExposeEvents(&view->impl->pendingExpose, &event);
+ } else if (event.type == PUGL_CONFIGURE) {
+ // Expand configure event to be dispatched after loop
+ view->impl->pendingConfigure = event;
+ view->frame.x = event.configure.x;
+ view->frame.y = event.configure.y;
+ view->frame.width = event.configure.width;
+ view->frame.height = event.configure.height;
+ } else if (event.type == PUGL_MAP && view->parent) {
+ XWindowAttributes attrs;
+ XGetWindowAttributes(view->impl->display, view->impl->win, &attrs);
+
+ const PuglEventConfigure configure = {
+ PUGL_CONFIGURE, 0, attrs.x, attrs.y, attrs.width, attrs.height};
+
+ puglDispatchEvent(view, (const PuglEvent*)&configure);
+ puglDispatchEvent(view, &event);
+ } else {
+ // Dispatch event to application immediately
+ puglDispatchEvent(view, &event);
+ }
+ }
+
+ return PUGL_SUCCESS;
+}
+
+#ifndef PUGL_DISABLE_DEPRECATED
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ return puglUpdate(view->world, 0.0);
+}
+#endif
+
+PuglStatus
+puglUpdate(PuglWorld* world, double timeout)
+{
+ const double startTime = puglGetTime(world);
+ PuglStatus st = PUGL_SUCCESS;
+
+ world->impl->dispatchingEvents = true;
+
+ if (timeout < 0.0) {
+ st = puglPollX11Socket(world, timeout);
+ st = st ? st : puglDispatchX11Events(world);
+ } else if (timeout <= 0.001) {
+ st = puglDispatchX11Events(world);
+ } else {
+ const double endTime = startTime + timeout - 0.001;
+ for (double t = startTime; t < endTime; t = puglGetTime(world)) {
+ if ((st = puglPollX11Socket(world, endTime - t)) ||
+ (st = puglDispatchX11Events(world))) {
+ break;
+ }
+ }
+ }
+
+ flushExposures(world);
+
+ world->impl->dispatchingEvents = false;
+
+ return st;
+}
+
+double
+puglGetTime(const PuglWorld* world)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ((double)ts.tv_sec + ts.tv_nsec / 1000000000.0) - world->startTime;
+}
+
+PuglStatus
+puglPostRedisplay(PuglView* view)
+{
+ const PuglRect rect = { 0, 0, view->frame.width, view->frame.height };
+
+ return puglPostRedisplayRect(view, rect);
+}
+
+PuglStatus
+puglPostRedisplayRect(PuglView* view, PuglRect rect)
+{
+ const PuglEventExpose event = {
+ PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height, 0
+ };
+
+ if (view->world->impl->dispatchingEvents) {
+ // Currently dispatching events, add/expand expose for the loop end
+ mergeExposeEvents(&view->impl->pendingExpose, (const PuglEvent*)&event);
+ } else if (view->visible) {
+ // Not dispatching events, send an X expose so we wake up next time
+ return puglSendEvent(view, (const PuglEvent*)&event);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglNativeView
+puglGetNativeWindow(PuglView* view)
+{
+ return (PuglNativeView)view->impl->win;
+}
+
+PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title)
+{
+ Display* display = view->world->impl->display;
+ const PuglX11Atoms* const atoms = &view->world->impl->atoms;
+
+ puglSetString(&view->title, title);
+
+ if (view->impl->win) {
+ XStoreName(display, view->impl->win, title);
+ XChangeProperty(display, view->impl->win, atoms->NET_WM_NAME,
+ atoms->UTF8_STRING, 8, PropModeReplace,
+ (const uint8_t*)title, (int)strlen(title));
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetFrame(PuglView* view, const PuglRect frame)
+{
+ view->frame = frame;
+
+ if (view->impl->win &&
+ !XMoveResizeWindow(view->world->impl->display, view->impl->win,
+ (int)frame.x, (int)frame.y,
+ (unsigned)frame.width, (unsigned)frame.height)) {
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetMinSize(PuglView* const view, const int width, const int height)
+{
+ Display* display = view->world->impl->display;
+
+ view->minWidth = width;
+ view->minHeight = height;
+
+ if (view->impl->win) {
+ XSizeHints sizeHints = getSizeHints(view);
+ XSetNormalHints(display, view->impl->win, &sizeHints);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetAspectRatio(PuglView* const view,
+ const int minX,
+ const int minY,
+ const int maxX,
+ const int maxY)
+{
+ Display* display = view->world->impl->display;
+
+ view->minAspectX = minX;
+ view->minAspectY = minY;
+ view->maxAspectX = maxX;
+ view->maxAspectY = maxY;
+
+ if (view->impl->win) {
+ XSizeHints sizeHints = getSizeHints(view);
+ XSetNormalHints(display, view->impl->win, &sizeHints);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+PuglStatus
+puglSetTransientFor(PuglView* view, PuglNativeView parent)
+{
+ Display* display = view->world->impl->display;
+
+ view->transientParent = parent;
+
+ if (view->impl->win) {
+ XSetTransientForHint(display, view->impl->win,
+ (Window)view->transientParent);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+const void*
+puglGetClipboard(PuglView* const view,
+ const char** const type,
+ size_t* const len)
+{
+ PuglInternals* const impl = view->impl;
+ const PuglX11Atoms* const atoms = &view->world->impl->atoms;
+
+ const Window owner = XGetSelectionOwner(impl->display, atoms->CLIPBOARD);
+ if (owner != None && owner != impl->win) {
+ // Clear internal selection
+ puglSetBlob(&view->clipboard, NULL, 0);
+
+ // Request selection from the owner
+ XConvertSelection(impl->display,
+ atoms->CLIPBOARD,
+ atoms->UTF8_STRING,
+ XA_PRIMARY,
+ impl->win,
+ CurrentTime);
+
+ // Run event loop until data is received
+ while (!view->clipboard.data) {
+ puglUpdate(view->world, -1.0);
+ }
+ }
+
+ return puglGetInternalClipboard(view, type, len);
+}
+
+PuglStatus
+puglSetClipboard(PuglView* const view,
+ const char* const type,
+ const void* const data,
+ const size_t len)
+{
+ PuglInternals* const impl = view->impl;
+ const PuglX11Atoms* const atoms = &view->world->impl->atoms;
+
+ PuglStatus st = puglSetInternalClipboard(view, type, data, len);
+ if (st) {
+ return st;
+ }
+
+ XSetSelectionOwner(impl->display, atoms->CLIPBOARD, impl->win, CurrentTime);
+ return PUGL_SUCCESS;
+}
+
+const PuglBackend*
+puglStubBackend(void)
+{
+ static const PuglBackend backend = {
+ puglX11StubConfigure,
+ puglStubCreate,
+ puglStubDestroy,
+ puglStubEnter,
+ puglStubLeave,
+ puglStubGetContext,
+ };
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/x11.h b/subprojects/d2tk/pugl/pugl/detail/x11.h
new file mode 100644
index 00000000..6b7a1508
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/x11.h
@@ -0,0 +1,83 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 x11.h Shared definitions for X11 implementation.
+*/
+
+#include "pugl/detail/types.h"
+#include "pugl/pugl.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ Atom CLIPBOARD;
+ Atom UTF8_STRING;
+ Atom WM_PROTOCOLS;
+ Atom WM_DELETE_WINDOW;
+ Atom PUGL_CLIENT_MSG;
+ Atom NET_WM_NAME;
+ Atom NET_WM_STATE;
+ Atom NET_WM_STATE_DEMANDS_ATTENTION;
+} PuglX11Atoms;
+
+typedef struct {
+ XID alarm;
+ PuglView* view;
+ uint64_t id;
+} PuglTimer;
+
+struct PuglWorldInternalsImpl {
+ Display* display;
+ PuglX11Atoms atoms;
+ XIM xim;
+ PuglTimer* timers;
+ size_t numTimers;
+ XID serverTimeCounter;
+ int syncEventBase;
+ bool syncSupported;
+ bool dispatchingEvents;
+};
+
+struct PuglInternalsImpl {
+ Display* display;
+ int screen;
+ XVisualInfo* vi;
+ Window win;
+ XIC xic;
+ PuglSurface* surface;
+ PuglEvent pendingConfigure;
+ PuglEvent pendingExpose;
+};
+
+static inline PuglStatus
+puglX11StubConfigure(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ XVisualInfo pat = {0};
+ int n = 0;
+
+ pat.screen = impl->screen;
+ impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n);
+
+ return PUGL_SUCCESS;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/x11_cairo.c b/subprojects/d2tk/pugl/pugl/detail/x11_cairo.c
new file mode 100644
index 00000000..0229d978
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/x11_cairo.c
@@ -0,0 +1,169 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 x11_cairo.c Cairo graphics backend for X11.
+*/
+
+#include "pugl/detail/types.h"
+#include "pugl/detail/x11.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_cairo.h"
+
+#include <X11/Xutil.h>
+#include <cairo-xlib.h>
+#include <cairo.h>
+
+#include <stdlib.h>
+
+typedef struct {
+ cairo_surface_t* back;
+ cairo_surface_t* front;
+ cairo_t* cr;
+} PuglX11CairoSurface;
+
+static void
+puglX11CairoClose(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ cairo_surface_destroy(surface->front);
+ cairo_surface_destroy(surface->back);
+ surface->front = surface->back = NULL;
+}
+
+static PuglStatus
+puglX11CairoOpen(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ surface->back = cairo_xlib_surface_create(impl->display,
+ impl->win,
+ impl->vi->visual,
+ (int)view->frame.width,
+ (int)view->frame.height);
+
+ surface->front = cairo_surface_create_similar(
+ surface->back,
+ cairo_surface_get_content(surface->back),
+ (int)view->frame.width,
+ (int)view->frame.height);
+
+ if (cairo_surface_status(surface->back) ||
+ cairo_surface_status(surface->front)) {
+ puglX11CairoClose(view);
+ return PUGL_CREATE_CONTEXT_FAILED;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11CairoCreate(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+
+ impl->surface = (cairo_surface_t*)calloc(1, sizeof(PuglX11CairoSurface));
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11CairoDestroy(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ puglX11CairoClose(view);
+ free(surface);
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11CairoEnter(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+ PuglStatus st = PUGL_SUCCESS;
+
+ if (expose && !(st = puglX11CairoOpen(view))) {
+ surface->cr = cairo_create(surface->front);
+
+ if (cairo_status(surface->cr)) {
+ st = PUGL_CREATE_CONTEXT_FAILED;
+ }
+ }
+
+ return st;
+}
+
+static PuglStatus
+puglX11CairoLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ if (expose) {
+ // Destroy front context and create a new one for drawing to the back
+ cairo_destroy(surface->cr);
+ surface->cr = cairo_create(surface->back);
+
+ // Clip to expose region
+ cairo_rectangle(surface->cr,
+ expose->x,
+ expose->y,
+ expose->width,
+ expose->height);
+ cairo_clip(surface->cr);
+
+ // Paint front onto back
+ cairo_set_source_surface(surface->cr, surface->front, 0, 0);
+ cairo_paint(surface->cr);
+
+ // Flush to X and close everything
+ cairo_destroy(surface->cr);
+ cairo_surface_flush(surface->back);
+ puglX11CairoClose(view);
+ surface->cr = NULL;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static void*
+puglX11CairoGetContext(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ return surface->cr;
+}
+
+const PuglBackend*
+puglCairoBackend(void)
+{
+ static const PuglBackend backend = {puglX11StubConfigure,
+ puglX11CairoCreate,
+ puglX11CairoDestroy,
+ puglX11CairoEnter,
+ puglX11CairoLeave,
+ puglX11CairoGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/detail/x11_gl.c b/subprojects/d2tk/pugl/pugl/detail/x11_gl.c
new file mode 100644
index 00000000..33a05df3
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/detail/x11_gl.c
@@ -0,0 +1,216 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 x11_gl.c OpenGL graphics backend for X11.
+*/
+
+#include "pugl/detail/types.h"
+#include "pugl/detail/x11.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_gl.h"
+#include "pugl/pugl_stub.h"
+
+#include <GL/glx.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ GLXFBConfig fb_config;
+ GLXContext ctx;
+ int double_buffered;
+} PuglX11GlSurface;
+
+static int
+puglX11GlHintValue(const int value)
+{
+ return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value;
+}
+
+static int
+puglX11GlGetAttrib(Display* const display,
+ GLXFBConfig fb_config,
+ const int attrib)
+{
+ int value = 0;
+ glXGetFBConfigAttrib(display, fb_config, attrib, &value);
+ return value;
+}
+
+static PuglStatus
+puglX11GlConfigure(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ const int screen = impl->screen;
+ Display* const display = impl->display;
+
+ PuglX11GlSurface* const surface =
+ (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface));
+ impl->surface = surface;
+
+ const int attrs[] = {
+ GLX_X_RENDERABLE, True,
+ GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_SAMPLES, view->hints[PUGL_SAMPLES],
+ GLX_RED_SIZE, puglX11GlHintValue(view->hints[PUGL_RED_BITS]),
+ GLX_GREEN_SIZE, puglX11GlHintValue(view->hints[PUGL_GREEN_BITS]),
+ GLX_BLUE_SIZE, puglX11GlHintValue(view->hints[PUGL_BLUE_BITS]),
+ GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints[PUGL_ALPHA_BITS]),
+ GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints[PUGL_DEPTH_BITS]),
+ GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints[PUGL_STENCIL_BITS]),
+ GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]),
+ None
+ };
+
+ int n_fbc = 0;
+ GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc);
+ if (n_fbc <= 0) {
+ return PUGL_CREATE_CONTEXT_FAILED;
+ }
+
+ surface->fb_config = fbc[0];
+ impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]);
+
+ char msg[128];
+
+ snprintf(
+ msg,
+ sizeof(msg),
+ "Using visual 0x%lX: R=%d G=%d B=%d A=%d D=%d DOUBLE=%d SAMPLES=%d\n",
+ impl->vi->visualid,
+ puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER),
+ puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES));
+
+ view->world->logFunc(view->world, PUGL_LOG_LEVEL_INFO, msg);
+
+ XFree(fbc);
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11GlCreate(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface;
+ Display* const display = impl->display;
+ GLXFBConfig fb_config = surface->fb_config;
+
+ const int ctx_attrs[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MAJOR],
+ GLX_CONTEXT_MINOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MINOR],
+ GLX_CONTEXT_FLAGS_ARB, (view->hints[PUGL_USE_DEBUG_CONTEXT]
+ ? GLX_CONTEXT_DEBUG_BIT_ARB
+ : 0),
+ GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints[PUGL_USE_COMPAT_PROFILE]
+ ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
+ : GLX_CONTEXT_CORE_PROFILE_BIT_ARB),
+ 0};
+
+ PFNGLXCREATECONTEXTATTRIBSARBPROC create_context =
+ (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress(
+ (const uint8_t*)"glXCreateContextAttribsARB");
+
+ PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
+ (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress(
+ (const uint8_t*)"glXSwapIntervalEXT");
+
+ surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs);
+ if (!surface->ctx) {
+ surface->ctx =
+ glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True);
+ }
+
+ if (!surface->ctx) {
+ return PUGL_CREATE_CONTEXT_FAILED;
+ }
+
+ const int swapInterval = view->hints[PUGL_SWAP_INTERVAL];
+ if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) {
+ glXSwapIntervalEXT(display, impl->win, swapInterval);
+ }
+
+ glXGetConfig(impl->display,
+ impl->vi,
+ GLX_DOUBLEBUFFER,
+ &surface->double_buffered);
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11GlDestroy(PuglView* view)
+{
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
+ if (surface) {
+ glXDestroyContext(view->impl->display, surface->ctx);
+ free(surface);
+ view->impl->surface = NULL;
+ }
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11GlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose))
+{
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
+ glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx);
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+puglX11GlLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
+
+ if (expose && surface->double_buffered) {
+ glXSwapBuffers(view->impl->display, view->impl->win);
+ }
+
+ glXMakeCurrent(view->impl->display, None, NULL);
+
+ return PUGL_SUCCESS;
+}
+
+PuglGlFunc
+puglGetProcAddress(const char* name)
+{
+ return glXGetProcAddress((const uint8_t*)name);
+}
+
+const PuglBackend* puglGlBackend(void)
+{
+ static const PuglBackend backend = {puglX11GlConfigure,
+ puglX11GlCreate,
+ puglX11GlDestroy,
+ puglX11GlEnter,
+ puglX11GlLeave,
+ puglStubGetContext};
+
+ return &backend;
+}
diff --git a/subprojects/d2tk/pugl/pugl/gl.h b/subprojects/d2tk/pugl/pugl/gl.h
index 9a6aeefe..55a55c4a 100644
--- a/subprojects/d2tk/pugl/pugl/gl.h
+++ b/subprojects/d2tk/pugl/pugl/gl.h
@@ -29,4 +29,3 @@
# endif
# include "GL/gl.h"
#endif
-
diff --git a/subprojects/d2tk/pugl/pugl/glu.h b/subprojects/d2tk/pugl/pugl/glu.h
index 0d3e8e1d..0ade70c9 100644
--- a/subprojects/d2tk/pugl/pugl/glu.h
+++ b/subprojects/d2tk/pugl/pugl/glu.h
@@ -15,7 +15,7 @@
*/
/**
- @file gl.h Portable header wrapper for glu.h.
+ @file glu.h Portable header wrapper for glu.h.
Unfortunately, GL includes vary across platforms so this header allows for
pure portable programs.
@@ -29,4 +29,3 @@
# endif
# include "GL/glu.h"
#endif
-
diff --git a/subprojects/d2tk/pugl/pugl/pugl.h b/subprojects/d2tk/pugl/pugl/pugl.h
index dbbad901..57e23fa7 100644
--- a/subprojects/d2tk/pugl/pugl/pugl.h
+++ b/subprojects/d2tk/pugl/pugl/pugl.h
@@ -1,5 +1,5 @@
/*
- Copyright 2012-2016 David Robillard <http://drobilla.net>
+ Copyright 2012-2020 David Robillard <http://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
@@ -15,12 +15,14 @@
*/
/**
- @file pugl.h API for Pugl, a minimal portable API for OpenGL.
+ @file pugl.h Pugl API.
*/
-#ifndef PUGL_H_INCLUDED
-#define PUGL_H_INCLUDED
+#ifndef PUGL_PUGL_H
+#define PUGL_PUGL_H
+#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#ifdef PUGL_SHARED
@@ -40,81 +42,94 @@
# define PUGL_API
#endif
+#ifndef PUGL_DISABLE_DEPRECATED
+# if defined(__clang__)
+# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("", rep)))
+# elif defined(__GNUC__)
+# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("Use " rep)))
+# else
+# define PUGL_DEPRECATED_BY(rep)
+# endif
+#endif
+
#ifdef __cplusplus
-extern "C" {
+# define PUGL_BEGIN_DECLS extern "C" {
+# define PUGL_END_DECLS }
#else
-# include <stdbool.h>
+# define PUGL_BEGIN_DECLS
+# define PUGL_END_DECLS
#endif
+PUGL_BEGIN_DECLS
+
/**
- @defgroup pugl Pugl
- A minimal portable API for OpenGL.
+ @defgroup pugl_api Pugl
+ A minimal portable API for embeddable GUIs.
@{
*/
/**
- A Pugl view.
-*/
-typedef struct PuglViewImpl PuglView;
+ A rectangle.
-/**
- A native window handle.
-
- On X11, this is a Window.
- On OSX, this is an NSView*.
- On Windows, this is a HWND.
+ This is used to describe things like view position and size. Pugl generally
+ uses coordinates where the top left corner is 0,0.
*/
-typedef intptr_t PuglNativeWindow;
+typedef struct {
+ double x;
+ double y;
+ double width;
+ double height;
+} PuglRect;
/**
- Handle for opaque user data.
-*/
-typedef void* PuglHandle;
+ @defgroup events Events
-/**
- Return status code.
-*/
-typedef enum {
- PUGL_SUCCESS = 0
-} PuglStatus;
+ Event definitions.
-/**
- Drawing context type.
-*/
-typedef enum {
- PUGL_GL = 0x1,
- PUGL_CAIRO = 0x2,
- PUGL_CAIRO_GL = 0x3
-} PuglContextType;
+ All updates to the view happen via events, which are dispatched to the
+ view's #PuglEventFunc by Pugl. Most events map directly to one from the
+ underlying window system, but some are constructed by Pugl itself so there
+ is not necessarily a direct correspondence.
-/**
- Convenience symbols for ASCII control characters.
+ @{
*/
-typedef enum {
- PUGL_CHAR_BACKSPACE = 0x08,
- PUGL_CHAR_ESCAPE = 0x1B,
- PUGL_CHAR_DELETE = 0x7F
-} PuglChar;
/**
Keyboard modifier flags.
*/
typedef enum {
- PUGL_MOD_SHIFT = 1, /**< Shift key */
- PUGL_MOD_CTRL = 1 << 1, /**< Control key */
- PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */
- PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */
+ PUGL_MOD_SHIFT = 1, ///< Shift key
+ PUGL_MOD_CTRL = 1 << 1, ///< Control key
+ PUGL_MOD_ALT = 1 << 2, ///< Alt/Option key
+ PUGL_MOD_SUPER = 1 << 3 ///< Mod4/Command/Windows key
} PuglMod;
/**
- Special (non-Unicode) keyboard keys.
+ Bitwise OR of #PuglMod values.
+*/
+typedef uint32_t PuglMods;
- The numerical values of these symbols occupy a reserved range of Unicode
- points, so it is possible to express either a PuglKey value or a Unicode
- character in the same variable. This is sometimes useful for interfacing
- with APIs that do not make this distinction.
+/**
+ Keyboard key codepoints.
+
+ All keys are identified by a Unicode code point in PuglEventKey::key. This
+ enumeration defines constants for special keys that do not have a standard
+ code point, and some convenience constants for control characters. Note
+ that all keys are handled in the same way, this enumeration is just for
+ convenience when writing hard-coded key bindings.
+
+ Keys that do not have a standard code point use values in the Private Use
+ Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications
+ must take care to not interpret these values beyond key detection, the
+ mapping used here is arbitrary and specific to Pugl.
*/
typedef enum {
+ // ASCII control codes
+ PUGL_KEY_BACKSPACE = 0x08,
+ PUGL_KEY_ESCAPE = 0x1B,
+ PUGL_KEY_DELETE = 0x7F,
+
+ // Unicode Private Use Area
PUGL_KEY_F1 = 0xE000,
PUGL_KEY_F2,
PUGL_KEY_F3,
@@ -137,454 +152,1255 @@ typedef enum {
PUGL_KEY_END,
PUGL_KEY_INSERT,
PUGL_KEY_SHIFT,
+ PUGL_KEY_SHIFT_L = PUGL_KEY_SHIFT,
+ PUGL_KEY_SHIFT_R,
PUGL_KEY_CTRL,
+ PUGL_KEY_CTRL_L = PUGL_KEY_CTRL,
+ PUGL_KEY_CTRL_R,
PUGL_KEY_ALT,
- PUGL_KEY_SUPER
+ PUGL_KEY_ALT_L = PUGL_KEY_ALT,
+ PUGL_KEY_ALT_R,
+ PUGL_KEY_SUPER,
+ PUGL_KEY_SUPER_L = PUGL_KEY_SUPER,
+ PUGL_KEY_SUPER_R,
+ PUGL_KEY_MENU,
+ PUGL_KEY_CAPS_LOCK,
+ PUGL_KEY_SCROLL_LOCK,
+ PUGL_KEY_NUM_LOCK,
+ PUGL_KEY_PRINT_SCREEN,
+ PUGL_KEY_PAUSE
} PuglKey;
/**
The type of a PuglEvent.
*/
typedef enum {
- PUGL_NOTHING, /**< No event */
- PUGL_BUTTON_PRESS, /**< Mouse button press */
- PUGL_BUTTON_RELEASE, /**< Mouse button release */
- PUGL_CONFIGURE, /**< View moved and/or resized */
- PUGL_EXPOSE, /**< View exposed, redraw required */
- PUGL_CLOSE, /**< Close view */
- PUGL_KEY_PRESS, /**< Key press */
- PUGL_KEY_RELEASE, /**< Key release */
- PUGL_ENTER_NOTIFY, /**< Pointer entered view */
- PUGL_LEAVE_NOTIFY, /**< Pointer left view */
- PUGL_MOTION_NOTIFY, /**< Pointer motion */
- PUGL_SCROLL, /**< Scroll */
- PUGL_FOCUS_IN, /**< Keyboard focus entered view */
- PUGL_FOCUS_OUT /**< Keyboard focus left view */
+ PUGL_NOTHING, ///< No event
+ PUGL_CREATE, ///< View created, a #PuglEventCreate
+ PUGL_DESTROY, ///< View destroyed, a #PuglEventDestroy
+ PUGL_CONFIGURE, ///< View moved/resized, a #PuglEventConfigure
+ PUGL_MAP, ///< View made visible, a #PuglEventMap
+ PUGL_UNMAP, ///< View made invisible, a #PuglEventUnmap
+ PUGL_UPDATE, ///< View ready to draw, a #PuglEventUpdate
+ PUGL_EXPOSE, ///< View must be drawn, a #PuglEventExpose
+ PUGL_CLOSE, ///< View will be closed, a #PuglEventClose
+ PUGL_FOCUS_IN, ///< Keyboard focus entered view, a #PuglEventFocus
+ PUGL_FOCUS_OUT, ///< Keyboard focus left view, a #PuglEventFocus
+ PUGL_KEY_PRESS, ///< Key pressed, a #PuglEventKey
+ PUGL_KEY_RELEASE, ///< Key released, a #PuglEventKey
+ PUGL_TEXT, ///< Character entered, a #PuglEventText
+ PUGL_POINTER_IN, ///< Pointer entered view, a #PuglEventCrossing
+ PUGL_POINTER_OUT, ///< Pointer left view, a #PuglEventCrossing
+ PUGL_BUTTON_PRESS, ///< Mouse button pressed, a #PuglEventButton
+ PUGL_BUTTON_RELEASE, ///< Mouse button released, a #PuglEventButton
+ PUGL_MOTION, ///< Pointer moved, a #PuglEventMotion
+ PUGL_SCROLL, ///< Scrolled, a #PuglEventScroll
+ PUGL_CLIENT, ///< Custom client message, a #PuglEventClient
+ PUGL_TIMER, ///< Timer triggered, a #PuglEventTimer
+
+#ifndef PUGL_DISABLE_DEPRECATED
+ PUGL_ENTER_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_IN") = PUGL_POINTER_IN,
+ PUGL_LEAVE_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_OUT") = PUGL_POINTER_OUT,
+ PUGL_MOTION_NOTIFY PUGL_DEPRECATED_BY("PUGL_MOTION") = PUGL_MOTION,
+#endif
+
} PuglEventType;
+/**
+ Common flags for all event types.
+*/
typedef enum {
- PUGL_IS_SEND_EVENT = 1
+ PUGL_IS_SEND_EVENT = 1 ///< Event is synthetic
} PuglEventFlag;
/**
+ Bitwise OR of #PuglEventFlag values.
+*/
+typedef uint32_t PuglEventFlags;
+
+/**
Reason for a PuglEventCrossing.
*/
typedef enum {
- PUGL_CROSSING_NORMAL, /**< Crossing due to pointer motion. */
- PUGL_CROSSING_GRAB, /**< Crossing due to a grab. */
- PUGL_CROSSING_UNGRAB /**< Crossing due to a grab release. */
+ PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion
+ PUGL_CROSSING_GRAB, ///< Crossing due to a grab
+ PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release
} PuglCrossingMode;
/**
Common header for all event structs.
*/
typedef struct {
- PuglEventType type; /**< Event type. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
+ PuglEventType type; ///< Event type
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
} PuglEventAny;
/**
- Button press or release event.
+ View create event.
+
+ This event is sent when a view is realized before it is first displayed,
+ with the graphics context entered. This is typically used for setting up
+ the graphics system, for example by loading OpenGL extensions.
- For event types PUGL_BUTTON_PRESS and PUGL_BUTTON_RELEASE.
+ This event type has no extra fields.
*/
-typedef struct {
- PuglEventType type; /**< PUGL_BUTTON_PRESS or PUGL_BUTTON_RELEASE. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- uint32_t time; /**< Time in milliseconds. */
- double x; /**< View-relative X coordinate. */
- double y; /**< View-relative Y coordinate. */
- double x_root; /**< Root-relative X coordinate. */
- double y_root; /**< Root-relative Y coordinate. */
- unsigned state; /**< Bitwise OR of PuglMod flags. */
- unsigned button; /**< 1-relative button number. */
-} PuglEventButton;
+typedef PuglEventAny PuglEventCreate;
/**
- Configure event for when window size or position has changed.
+ View destroy event.
+
+ This event is the counterpart to #PuglEventCreate, and it is sent when the
+ view is being destroyed. This is typically used for tearing down the
+ graphics system, or otherwise freeing any resources allocated when the
+ create event was handled.
+
+ This is the last event sent to any view, and immediately after it is
+ processed, the view is destroyed and may no longer be used.
+
+ This event type has no extra fields.
+*/
+typedef PuglEventAny PuglEventDestroy;
+
+/**
+ View resize or move event.
+
+ A configure event is sent whenever the view is resized or moved. When a
+ configure event is received, the graphics context is active but not set up
+ for drawing. For example, it is valid to adjust the OpenGL viewport or
+ otherwise configure the context, but not to draw anything.
*/
typedef struct {
- PuglEventType type; /**< PUGL_CONFIGURE. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- double x; /**< New parent-relative X coordinate. */
- double y; /**< New parent-relative Y coordinate. */
- double width; /**< New width. */
- double height; /**< New height. */
+ PuglEventType type; ///< #PUGL_CONFIGURE
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double x; ///< New parent-relative X coordinate
+ double y; ///< New parent-relative Y coordinate
+ double width; ///< New width
+ double height; ///< New height
} PuglEventConfigure;
/**
+ View show event.
+
+ This event is sent when a view is mapped to the screen and made visible.
+
+ This event type has no extra fields.
+*/
+typedef PuglEventAny PuglEventMap;
+
+/**
+ View hide event.
+
+ This event is sent when a view is unmapped from the screen and made
+ invisible.
+
+ This event type has no extra fields.
+*/
+typedef PuglEventAny PuglEventUnmap;
+
+/**
+ View update event.
+
+ This event is sent to every view near the end of a main loop iteration when
+ any pending exposures are about to be redrawn. It is typically used to mark
+ regions to expose with puglPostRedisplay() or puglPostRedisplayRect(). For
+ example, to continuously animate, a view calls puglPostRedisplay() when an
+ update event is received, and it will then shortly receive an expose event.
+*/
+typedef PuglEventAny PuglEventUpdate;
+
+/**
Expose event for when a region must be redrawn.
+
+ When an expose event is received, the graphics context is active, and the
+ view must draw the entire specified region. The contents of the region are
+ undefined, there is no preservation of anything drawn previously.
*/
typedef struct {
- PuglEventType type; /**< PUGL_EXPOSE. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- double x; /**< View-relative X coordinate. */
- double y; /**< View-relative Y coordinate. */
- double width; /**< Width of exposed region. */
- double height; /**< Height of exposed region. */
- int count; /**< Number of expose events to follow. */
+ PuglEventType type; ///< #PUGL_EXPOSE
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double width; ///< Width of exposed region
+ double height; ///< Height of exposed region
+ int count; ///< Number of expose events to follow
} PuglEventExpose;
/**
- Window close event.
+ View close event.
+
+ This event is sent when the view is to be closed, for example when the user
+ clicks the close button.
+
+ This event type has no extra fields.
+*/
+typedef PuglEventAny PuglEventClose;
+
+/**
+ Keyboard focus event.
+
+ This event is sent whenever the view gains or loses the keyboard focus. The
+ view with the keyboard focus will receive any key press or release events.
*/
typedef struct {
- PuglEventType type; /**< PUGL_CLOSE. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
-} PuglEventClose;
+ PuglEventType type; ///< #PUGL_FOCUS_IN or #PUGL_FOCUS_OUT
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ bool grab; ///< True iff this is a grab/ungrab event
+} PuglEventFocus;
/**
- Key press/release event.
+ Key press or release event.
- Keys that correspond to a Unicode character have `character` and `utf8` set.
- Other keys will have `character` 0, but `special` may be set if this is a
- known special key.
+ This event represents low-level key presses and releases. This can be used
+ for "direct" keyboard handing like key bindings, but must not be interpreted
+ as text input.
- A key press may be part of a multi-key sequence to generate a wide
- character. If `filter` is set, this event is part of a multi-key sequence
- and should be ignored if the application is reading textual input.
- Following the series of filtered press events, a press event with
- `character` and `utf8` (but `keycode` 0) will be sent. This event will have
- no corresponding release event.
+ Keys are represented portably as Unicode code points, using the "natural"
+ code point for the key where possible (see #PuglKey for details). The #key
+ field is the code for the pressed key, without any modifiers applied. For
+ example, a press or release of the 'A' key will have #key 97 ('a')
+ regardless of whether shift or control are being held.
- Generally, an application should either work with raw keyboard press/release
- events based on `keycode` (ignoring events with `keycode` 0), or
- read textual input based on `character` or `utf8` (ignoring releases and
- events with `filter` 1). Note that blindly appending `utf8` will yield
- incorrect text, since press events are sent for both individually composed
- keys and the resulting synthetic multi-byte press.
+ Alternatively, the raw #keycode can be used to work directly with physical
+ keys, but note that this value is not portable and differs between platforms
+ and hardware.
*/
typedef struct {
- PuglEventType type; /**< PUGL_KEY_PRESS or PUGL_KEY_RELEASE. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- uint32_t time; /**< Time in milliseconds. */
- double x; /**< View-relative X coordinate. */
- double y; /**< View-relative Y coordinate. */
- double x_root; /**< Root-relative X coordinate. */
- double y_root; /**< Root-relative Y coordinate. */
- unsigned state; /**< Bitwise OR of PuglMod flags. */
- unsigned keycode; /**< Raw key code. */
- uint32_t character; /**< Unicode character code, or 0. */
- PuglKey special; /**< Special key, or 0. */
- uint8_t utf8[8]; /**< UTF-8 string. */
- bool filter; /**< True if part of a multi-key sequence. */
+ PuglEventType type; ///< #PUGL_KEY_PRESS or #PUGL_KEY_RELEASE
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double time; ///< Time in seconds
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double xRoot; ///< Root-relative X coordinate
+ double yRoot; ///< Root-relative Y coordinate
+ PuglMods state; ///< Bitwise OR of #PuglMod flags
+ uint32_t keycode; ///< Raw key code
+ uint32_t key; ///< Unshifted Unicode character code, or 0
} PuglEventKey;
/**
- Pointer crossing event (enter and leave).
+ Character input event.
+
+ This event represents text input, usually as the result of a key press. The
+ text is given both as a Unicode character code and a UTF-8 string.
+
+ Note that this event is generated by the platform's input system, so there
+ is not necessarily a direct correspondence between text events and physical
+ key presses. For example, with some input methods a sequence of several key
+ presses will generate a single character.
+*/
+typedef struct {
+ PuglEventType type; ///< #PUGL_TEXT
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double time; ///< Time in seconds
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double xRoot; ///< Root-relative X coordinate
+ double yRoot; ///< Root-relative Y coordinate
+ PuglMods state; ///< Bitwise OR of #PuglMod flags
+ uint32_t keycode; ///< Raw key code
+ uint32_t character; ///< Unicode character code
+ char string[8]; ///< UTF-8 string
+} PuglEventText;
+
+/**
+ Pointer enter or leave event.
+
+ This event is sent when the pointer enters or leaves the view. This can
+ happen for several reasons (not just the user dragging the pointer over the
+ window edge), as described by the #mode field.
*/
typedef struct {
- PuglEventType type; /**< PUGL_ENTER_NOTIFY or PUGL_LEAVE_NOTIFY. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- uint32_t time; /**< Time in milliseconds. */
- double x; /**< View-relative X coordinate. */
- double y; /**< View-relative Y coordinate. */
- double x_root; /**< Root-relative X coordinate. */
- double y_root; /**< Root-relative Y coordinate. */
- unsigned state; /**< Bitwise OR of PuglMod flags. */
- PuglCrossingMode mode; /**< Reason for crossing. */
+ PuglEventType type; ///< #PUGL_POINTER_IN or #PUGL_POINTER_OUT
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double time; ///< Time in seconds
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double xRoot; ///< Root-relative X coordinate
+ double yRoot; ///< Root-relative Y coordinate
+ PuglMods state; ///< Bitwise OR of #PuglMod flags
+ PuglCrossingMode mode; ///< Reason for crossing
} PuglEventCrossing;
/**
+ Button press or release event.
+*/
+typedef struct {
+ PuglEventType type; ///< #PUGL_BUTTON_PRESS or #PUGL_BUTTON_RELEASE
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double time; ///< Time in seconds
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double xRoot; ///< Root-relative X coordinate
+ double yRoot; ///< Root-relative Y coordinate
+ PuglMods state; ///< Bitwise OR of #PuglMod flags
+ uint32_t button; ///< Button number starting from 1
+} PuglEventButton;
+
+/**
Pointer motion event.
*/
typedef struct {
- PuglEventType type; /**< PUGL_MOTION_NOTIFY. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- uint32_t time; /**< Time in milliseconds. */
- double x; /**< View-relative X coordinate. */
- double y; /**< View-relative Y coordinate. */
- double x_root; /**< Root-relative X coordinate. */
- double y_root; /**< Root-relative Y coordinate. */
- unsigned state; /**< Bitwise OR of PuglMod flags. */
- bool is_hint; /**< True iff this event is a motion hint. */
- bool focus; /**< True iff this is the focused window. */
+ PuglEventType type; ///< #PUGL_MOTION
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double time; ///< Time in seconds
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double xRoot; ///< Root-relative X coordinate
+ double yRoot; ///< Root-relative Y coordinate
+ PuglMods state; ///< Bitwise OR of #PuglMod flags
+ bool isHint; ///< True iff this event is a motion hint
+ bool focus; ///< True iff this is the focused view
} PuglEventMotion;
/**
Scroll event.
The scroll distance is expressed in "lines", an arbitrary unit that
- corresponds to a single tick of a detented mouse wheel. For example, `dy` =
+ corresponds to a single tick of a detented mouse wheel. For example, #dy =
1.0 scrolls 1 line up. Some systems and devices support finer resolution
and/or higher values for fast scrolls, so programs should handle any value
gracefully.
- */
+*/
typedef struct {
- PuglEventType type; /**< PUGL_SCROLL. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- uint32_t time; /**< Time in milliseconds. */
- double x; /**< View-relative X coordinate. */
- double y; /**< View-relative Y coordinate. */
- double x_root; /**< Root-relative X coordinate. */
- double y_root; /**< Root-relative Y coordinate. */
- unsigned state; /**< Bitwise OR of PuglMod flags. */
- double dx; /**< Scroll X distance in lines. */
- double dy; /**< Scroll Y distance in lines. */
+ PuglEventType type; ///< #PUGL_SCROLL
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ double time; ///< Time in seconds
+ double x; ///< View-relative X coordinate
+ double y; ///< View-relative Y coordinate
+ double xRoot; ///< Root-relative X coordinate
+ double yRoot; ///< Root-relative Y coordinate
+ PuglMods state; ///< Bitwise OR of #PuglMod flags
+ double dx; ///< Scroll X distance in lines
+ double dy; ///< Scroll Y distance in lines
} PuglEventScroll;
/**
- Keyboard focus event.
+ Custom client message event.
+
+ This can be used to send a custom message to a view, which is delivered via
+ the window system and processed in the event loop as usual. Among other
+ things, this makes it possible to wake up the event loop for any reason.
*/
typedef struct {
- PuglEventType type; /**< PUGL_FOCUS_IN or PUGL_FOCUS_OUT. */
- PuglView* view; /**< View that received this event. */
- uint32_t flags; /**< Bitwise OR of PuglEventFlag values. */
- bool grab; /**< True iff this is a grab/ungrab event. */
-} PuglEventFocus;
+ PuglEventType type; ///< #PUGL_CLIENT
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ uintptr_t data1; ///< Client-specific data
+ uintptr_t data2; ///< Client-specific data
+} PuglEventClient;
/**
- Interface event.
+ Timer event.
- This is a union of all event structs. The `type` must be checked to
- determine which fields are safe to access. A pointer to PuglEvent can
- either be cast to the appropriate type, or the union members used.
+ This event is sent at the regular interval specified in the call to
+ puglStartTimer() that activated it.
+
+ The #id is the application-specific ID given to puglStartTimer() which
+ distinguishes this timer from others. It should always be checked in the
+ event handler, even in applications that register only one timer.
+*/
+typedef struct {
+ PuglEventType type; ///< #PUGL_TIMER
+ PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values
+ uintptr_t id; ///< Timer ID
+} PuglEventTimer;
+
+/**
+ View event.
+
+ This is a union of all event types. The #type must be checked to determine
+ which fields are safe to access. A pointer to PuglEvent can either be cast
+ to the appropriate type, or the union members used.
+
+ The graphics system may only be accessed when handling certain events. The
+ graphics context is active for #PUGL_CREATE, #PUGL_DESTROY, #PUGL_CONFIGURE,
+ and #PUGL_EXPOSE, but only enabled for drawing for #PUGL_EXPOSE.
*/
typedef union {
- PuglEventType type; /**< Event type. */
- PuglEventAny any; /**< Valid for all event types. */
- PuglEventButton button; /**< PUGL_BUTTON_PRESS, PUGL_BUTTON_RELEASE. */
- PuglEventConfigure configure; /**< PUGL_CONFIGURE. */
- PuglEventExpose expose; /**< PUGL_EXPOSE. */
- PuglEventClose close; /**< PUGL_CLOSE. */
- PuglEventKey key; /**< PUGL_KEY_PRESS, PUGL_KEY_RELEASE. */
- PuglEventCrossing crossing; /**< PUGL_ENTER_NOTIFY, PUGL_LEAVE_NOTIFY. */
- PuglEventMotion motion; /**< PUGL_MOTION_NOTIFY. */
- PuglEventScroll scroll; /**< PUGL_SCROLL. */
- PuglEventFocus focus; /**< PUGL_FOCUS_IN, PUGL_FOCUS_OUT. */
+ PuglEventAny any; ///< Valid for all event types
+ PuglEventType type; ///< Event type
+ PuglEventButton button; ///< #PUGL_BUTTON_PRESS, #PUGL_BUTTON_RELEASE
+ PuglEventConfigure configure; ///< #PUGL_CONFIGURE
+ PuglEventExpose expose; ///< #PUGL_EXPOSE
+ PuglEventKey key; ///< #PUGL_KEY_PRESS, #PUGL_KEY_RELEASE
+ PuglEventText text; ///< #PUGL_TEXT
+ PuglEventCrossing crossing; ///< #PUGL_POINTER_IN, #PUGL_POINTER_OUT
+ PuglEventMotion motion; ///< #PUGL_MOTION
+ PuglEventScroll scroll; ///< #PUGL_SCROLL
+ PuglEventFocus focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT
+ PuglEventClient client; ///< #PUGL_CLIENT
+ PuglEventTimer timer; ///< #PUGL_TIMER
} PuglEvent;
/**
- @name Initialization
- Configuration functions which must be called before creating a window.
+ @}
+ @defgroup status Status
+
+ Status codes and error handling.
+
@{
*/
/**
- Create a Pugl view.
+ Return status code.
+*/
+typedef enum {
+ PUGL_SUCCESS, ///< Success
+ PUGL_FAILURE, ///< Non-fatal failure
+ PUGL_UNKNOWN_ERROR, ///< Unknown system error
+ PUGL_BAD_BACKEND, ///< Invalid or missing backend
+ PUGL_BAD_PARAMETER, ///< Invalid parameter
+ PUGL_BACKEND_FAILED, ///< Backend initialisation failed
+ PUGL_REGISTRATION_FAILED, ///< Class registration failed
+ PUGL_REALIZE_FAILED, ///< System view realization failed
+ PUGL_SET_FORMAT_FAILED, ///< Failed to set pixel format
+ PUGL_CREATE_CONTEXT_FAILED, ///< Failed to create drawing context
+ PUGL_UNSUPPORTED_TYPE, ///< Unsupported data type
+} PuglStatus;
- To create a window, call the various puglInit* functions as necessary, then
- call puglCreateWindow().
+/**
+ Return a string describing a status code.
+*/
+PUGL_API
+const char*
+puglStrerror(PuglStatus status);
- @param pargc Pointer to argument count (currently unused).
- @param argv Arguments (currently unused).
- @return A newly created view.
+/**
+ @}
+ @defgroup world World
+
+ The top-level context of a Pugl application or plugin.
+
+ The world contains all library-wide state. There is no static data in Pugl,
+ so it is safe to use multiple worlds in a single process. This is to
+ facilitate plugins or other situations where it is not possible to share a
+ world, but a single world should be shared for all views where possible.
+
+ @{
*/
-PUGL_API PuglView*
-puglInit(int* pargc, char** argv);
/**
- Set the window class name before creating a window.
+ The "world" of application state.
+
+ The world represents everything that is not associated with a particular
+ view. Several worlds can be created in a single process, but code using
+ different worlds must be isolated so they are never mixed. Views are
+ strongly associated with the world they were created in.
*/
-PUGL_API void
-puglInitWindowClass(PuglView* view, const char* name);
+typedef struct PuglWorldImpl PuglWorld;
/**
- Set the parent window before creating a window (for embedding).
+ Handle for the world's opaque user data.
*/
-PUGL_API void
-puglInitWindowParent(PuglView* view, PuglNativeWindow parent);
+typedef void* PuglWorldHandle;
/**
- Set the window size before creating a window.
+ The type of a PuglWorld.
*/
-PUGL_API void
-puglInitWindowSize(PuglView* view, int width, int height);
+typedef enum {
+ PUGL_PROGRAM, ///< Top-level application
+ PUGL_MODULE ///< Plugin or module within a larger application
+} PuglWorldType;
/**
- Set the minimum window size before creating a window.
+ World flags.
*/
-PUGL_API void
-puglInitWindowMinSize(PuglView* view, int width, int height);
+typedef enum {
+ /**
+ Set up support for threads if necessary.
+
+ - X11: Calls XInitThreads() which is required for some drivers.
+ */
+ PUGL_WORLD_THREADS = 1 << 0
+} PuglWorldFlag;
/**
- Set the window aspect ratio range before creating a window.
+ Bitwise OR of #PuglWorldFlag values.
+*/
+typedef uint32_t PuglWorldFlags;
- The x and y values here represent a ratio of width to height. To set a
- fixed aspect ratio, set the minimum and maximum values to the same ratio.
+/**
+ A log message level, compatible with syslog.
+*/
+typedef enum {
+ PUGL_LOG_LEVEL_ERR = 3, ///< Error
+ PUGL_LOG_LEVEL_WARNING = 4, ///< Warning
+ PUGL_LOG_LEVEL_INFO = 6, ///< Informational message
+ PUGL_LOG_LEVEL_DEBUG = 7 ///< Debug message
+} PuglLogLevel;
+
+/**
+ A function called to report log messages.
+
+ @param world The world that produced this log message.
+ @param level Log level.
+ @param msg Message string.
+*/
+typedef void (*PuglLogFunc)(PuglWorld* world,
+ PuglLogLevel level,
+ const char* msg);
+
+/**
+ Create a new world.
+
+ @param type The type, which dictates what this world is responsible for.
+ @param flags Flags to control world features.
+ @return A new world, which must be later freed with puglFreeWorld().
+*/
+PUGL_API PuglWorld*
+puglNewWorld(PuglWorldType type, PuglWorldFlags flags);
+
+/**
+ Free a world allocated with puglNewWorld().
*/
PUGL_API void
-puglInitWindowAspectRatio(PuglView* view,
- int min_x,
- int min_y,
- int max_x,
- int max_y);
+puglFreeWorld(PuglWorld* world);
/**
- Enable or disable resizing before creating a window.
+ Set the user data for the world.
+
+ This is usually a pointer to a struct that contains all the state which must
+ be accessed by several views.
+
+ The handle is opaque to Pugl and is not interpreted in any way.
*/
PUGL_API void
-puglInitResizable(PuglView* view, bool resizable);
+puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle);
/**
- Set transient parent before creating a window.
+ Get the user data for the world.
+*/
+PUGL_API PuglWorldHandle
+puglGetWorldHandle(PuglWorld* world);
- On X11, parent must be a Window.
- On OSX, parent must be an NSView*.
+/**
+ Return a pointer to the native handle of the world.
+
+ @return
+ - X11: A pointer to the `Display`.
+ - MacOS: `NULL`.
+ - Windows: The `HMODULE` of the calling process.
+*/
+PUGL_API void*
+puglGetNativeWorld(PuglWorld* world);
+
+/**
+ Set the function to call to log a message.
+
+ This will be called to report any log messages generated internally by Pugl
+ which are enabled according to the log level.
+*/
+PUGL_API PuglStatus
+puglSetLogFunc(PuglWorld* world, PuglLogFunc logFunc);
+
+/**
+ Set the level of log messages to emit.
+
+ Any log messages with a level less than or equal to `level` will be emitted.
+*/
+PUGL_API PuglStatus
+puglSetLogLevel(PuglWorld* world, PuglLogLevel level);
+
+/**
+ Set the class name of the application.
+
+ This is a stable identifier for the application, used as the window
+ class/instance name on X11 and Windows. It is not displayed to the user,
+ but can be used in scripts and by window managers, so it should be the same
+ for every instance of the application, but different from other
+ applications.
+*/
+PUGL_API PuglStatus
+puglSetClassName(PuglWorld* world, const char* name);
+
+/**
+ Return the time in seconds.
+
+ This is a monotonically increasing clock with high resolution. The returned
+ time is only useful to compare against other times returned by this
+ function, its absolute value has no meaning.
+*/
+PUGL_API double
+puglGetTime(const PuglWorld* world);
+
+/**
+ Update by processing events from the window system.
+
+ This function is a single iteration of the main loop, and should be called
+ repeatedly to update all views.
+
+ If a positive timeout is given, then events will be processed for that
+ amount of time, starting from when this function was called. For purely
+ event-driven programs, a timeout of -1.0 can be used to block indefinitely
+ until something happens. For continuously animating programs, a timeout
+ that is a reasonable fraction of the ideal frame period should be used, to
+ minimise input latency by ensuring that as many input events are consumed as
+ possible before drawing. Plugins should always use a timeout of 0.0 to
+ avoid blocking the host.
+
+ @param world The world to update.
+
+ @param timeout Maximum time to wait, in seconds. If zero, the call returns
+ immediately, if negative, the call blocks indefinitely.
+
+ @return #PUGL_SUCCESS if events are read, #PUGL_FAILURE if not, or an error.
+*/
+PUGL_API PuglStatus
+puglUpdate(PuglWorld* world, double timeout);
+
+/**
+ @}
+
+ @defgroup view View
+
+ A drawable region that receives events.
+
+ A view can be thought of as a window, but does not necessarily correspond to
+ a top-level window in a desktop environment. For example, a view can be
+ embedded in some other window, or represent an embedded system where there
+ is no concept of multiple windows at all.
+
+ @{
+*/
+
+/**
+ A drawable region that receives events.
+*/
+typedef struct PuglViewImpl PuglView;
+
+/**
+ A graphics backend.
+
+ The backend dictates how graphics are set up for a view, and how drawing is
+ performed. A backend must be set by calling puglSetBackend() before
+ realising a view.
+
+ If you are using a local copy of Pugl, it is possible to implement a custom
+ backend. See the definition of `PuglBackendImpl` in the source code for
+ details.
+*/
+typedef struct PuglBackendImpl PuglBackend;
+
+/**
+ A native view handle.
+
+ X11: This is a `Window`.
+
+ MacOS: This is a pointer to an `NSView*`.
+
+ Windows: This is a `HWND`.
+*/
+typedef uintptr_t PuglNativeView;
+
+/**
+ Handle for a view's opaque user data.
+*/
+typedef void* PuglHandle;
+
+/**
+ A hint for configuring a view.
+*/
+typedef enum {
+ PUGL_USE_COMPAT_PROFILE, ///< Use compatible (not core) OpenGL profile
+ PUGL_USE_DEBUG_CONTEXT, ///< True to use a debug OpenGL context
+ PUGL_CONTEXT_VERSION_MAJOR, ///< OpenGL context major version
+ PUGL_CONTEXT_VERSION_MINOR, ///< OpenGL context minor version
+ PUGL_RED_BITS, ///< Number of bits for red channel
+ PUGL_GREEN_BITS, ///< Number of bits for green channel
+ PUGL_BLUE_BITS, ///< Number of bits for blue channel
+ PUGL_ALPHA_BITS, ///< Number of bits for alpha channel
+ PUGL_DEPTH_BITS, ///< Number of bits for depth buffer
+ PUGL_STENCIL_BITS, ///< Number of bits for stencil buffer
+ PUGL_SAMPLES, ///< Number of samples per pixel (AA)
+ PUGL_DOUBLE_BUFFER, ///< True if double buffering should be used
+ PUGL_SWAP_INTERVAL, ///< Number of frames between buffer swaps
+ PUGL_RESIZABLE, ///< True if view should be resizable
+ PUGL_IGNORE_KEY_REPEAT, ///< True if key repeat events are ignored
+
+ PUGL_NUM_VIEW_HINTS
+} PuglViewHint;
+
+/**
+ A special view hint value.
+*/
+typedef enum {
+ PUGL_DONT_CARE = -1, ///< Use best available value
+ PUGL_FALSE = 0, ///< Explicitly false
+ PUGL_TRUE = 1 ///< Explicitly true
+} PuglViewHintValue;
+
+/**
+ A function called when an event occurs.
+*/
+typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event);
+
+/**
+ @name Setup
+ Functions for creating and destroying a view.
+ @{
+*/
+
+/**
+ Create a new view.
+
+ A newly created view does not correspond to a real system view or window.
+ It must first be configured, then the system view can be created with
+ puglRealize().
+*/
+PUGL_API PuglView*
+puglNewView(PuglWorld* world);
+
+/**
+ Free a view created with puglNewView().
*/
PUGL_API void
-puglInitTransientFor(PuglView* view, uintptr_t parent);
+puglFreeView(PuglView* view);
/**
- Set the context type before creating a window.
+ Return the world that `view` is a part of.
+*/
+PUGL_API PuglWorld*
+puglGetWorld(PuglView* view);
+
+/**
+ Set the user data for a view.
+
+ This is usually a pointer to a struct that contains all the state which must
+ be accessed by a view. Everything needed to process events should be stored
+ here, not in static variables.
+
+ The handle is opaque to Pugl and is not interpreted in any way.
*/
PUGL_API void
-puglInitContextType(PuglView* view, PuglContextType type);
+puglSetHandle(PuglView* view, PuglHandle handle);
+
+/**
+ Get the user data for a view.
+*/
+PUGL_API PuglHandle
+puglGetHandle(PuglView* view);
+
+/**
+ Set the graphics backend to use for a view.
+
+ This must be called once to set the graphics backend before calling
+ puglRealize().
+
+ Pugl includes the following backends:
+
+ - puglGlBackend(), declared in pugl_gl.h
+ - puglCairoBackend(), declared in pugl_cairo.h
+
+ Note that backends are modular and not compiled into the main Pugl library
+ to avoid unnecessary dependencies. To use a particular backend,
+ applications must link against the appropriate backend library, or be sure
+ to compile in the appropriate code if using a local copy of Pugl.
+*/
+PUGL_API PuglStatus
+puglSetBackend(PuglView* view, const PuglBackend* backend);
+
+/**
+ Set the function to call when an event occurs.
+*/
+PUGL_API PuglStatus
+puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc);
+
+/**
+ Set a hint to configure view properties.
+
+ This only has an effect when called before puglRealize().
+*/
+PUGL_API PuglStatus
+puglSetViewHint(PuglView* view, PuglViewHint hint, int value);
/**
@}
+ @anchor frame
+ @name Frame
+ Functions for working with the position and size of a view.
+ @{
+*/
+
+/**
+ Get the current position and size of the view.
+
+ The position is in screen coordinates with an upper left origin.
+*/
+PUGL_API PuglRect
+puglGetFrame(const PuglView* view);
+
+/**
+ Set the current position and size of the view.
+
+ The position is in screen coordinates with an upper left origin.
+*/
+PUGL_API PuglStatus
+puglSetFrame(PuglView* view, PuglRect frame);
+
+/**
+ Set the minimum size of the view.
+
+ If an initial minimum size is known, this should be called before
+ puglRealize() to avoid stutter, though it can be called afterwards as well.
+*/
+PUGL_API PuglStatus
+puglSetMinSize(PuglView* view, int width, int height);
+
+/**
+ Set the view aspect ratio range.
+
+ The x and y values here represent a ratio of width to height. To set a
+ fixed aspect ratio, set the minimum and maximum values to the same ratio.
+
+ Note that setting different minimum and maximum constraints does not
+ currenty work on MacOS (the minimum is used), so only setting a fixed aspect
+ ratio works properly across all platforms.
+
+ If an initial aspect ratio is known, this should be called before
+ puglRealize() to avoid stutter, though it can be called afterwards as well.
*/
+PUGL_API PuglStatus
+puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY);
/**
+ @}
@name Windows
- Functions for creating and managing a visible window for a view.
+ Functions for working with system views and the window hierarchy.
@{
*/
/**
- Create a window with the settings given by the various puglInit functions.
+ Set the title of the window.
- @return 1 (pugl does not currently support multiple windows).
+ This only makes sense for non-embedded views that will have a corresponding
+ top-level window, and sets the title, typically displayed in the title bar
+ or in window switchers.
*/
-PUGL_API int
-puglCreateWindow(PuglView* view, const char* title);
+PUGL_API PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title);
/**
- Show the current window.
+ Set the parent window for embedding a view in an existing window.
+
+ This must be called before puglRealize(), reparenting is not supported.
*/
-PUGL_API void
+PUGL_API PuglStatus
+puglSetParentWindow(PuglView* view, PuglNativeView parent);
+
+/**
+ Set the transient parent of the window.
+
+ Set this for transient children like dialogs, to have them properly
+ associated with their parent window. This should be called before
+ puglRealize().
+*/
+PUGL_API PuglStatus
+puglSetTransientFor(PuglView* view, PuglNativeView parent);
+
+/**
+ Realise a view by creating a corresponding system view or window.
+
+ After this call, the (initially invisible) underlying system view exists and
+ can be accessed with puglGetNativeWindow(). There is currently no
+ corresponding unrealize function, the system view will be destroyed along
+ with the view when puglFreeView() is called.
+
+ The view should be fully configured using the above functions before this is
+ called. This function may only be called once per view.
+*/
+PUGL_API PuglStatus
+puglRealize(PuglView* view);
+
+/**
+ Show the view.
+
+ If the view has not yet been realized, the first call to this function will
+ do so automatically.
+
+ If the view is currently hidden, it will be shown and possibly raised to the
+ top depending on the platform.
+*/
+PUGL_API PuglStatus
puglShowWindow(PuglView* view);
/**
Hide the current window.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglHideWindow(PuglView* view);
/**
+ Return true iff the view is currently visible.
+*/
+PUGL_API bool
+puglGetVisible(const PuglView* view);
+
+/**
Return the native window handle.
*/
-PUGL_API PuglNativeWindow
+PUGL_API PuglNativeView
puglGetNativeWindow(PuglView* view);
/**
@}
+ @name Graphics
+ Functions for working with the graphics context and scheduling redisplays.
+ @{
*/
/**
- Set the handle to be passed to all callbacks.
+ Get the graphics context.
+
+ This is a backend-specific context used for drawing if the backend graphics
+ API requires one. It is only available during an expose.
- This is generally a pointer to a struct which contains all necessary state.
- Everything needed in callbacks should be here, not in static variables.
+ @return
+ - OpenGL: `NULL`.
+ - Cairo: A pointer to a
+ [`cairo_t`](http://www.cairographics.org/manual/cairo-cairo-t.html).
*/
-PUGL_API void
-puglSetHandle(PuglView* view, PuglHandle handle);
+PUGL_API void*
+puglGetContext(PuglView* view);
/**
- Get the handle to be passed to all callbacks.
+ Request a redisplay for the entire view.
+
+ This will cause an expose event to be dispatched later. If called from
+ within the event handler, the expose should arrive at the end of the current
+ event loop iteration, though this is not strictly guaranteed on all
+ platforms. If called elsewhere, an expose will be enqueued to be processed
+ in the next event loop iteration.
*/
-PUGL_API PuglHandle
-puglGetHandle(PuglView* view);
+PUGL_API PuglStatus
+puglPostRedisplay(PuglView* view);
/**
- Return true iff the view is currently visible.
+ Request a redisplay of the given rectangle within the view.
+
+ This has the same semantics as puglPostRedisplay(), but allows giving a
+ precise region for redrawing only a portion of the view.
+*/
+PUGL_API PuglStatus
+puglPostRedisplayRect(PuglView* view, PuglRect rect);
+
+/**
+ @}
+ @anchor interaction
+ @name Interaction
+ Functions for interacting with the user and window system.
+ @{
+*/
+
+/**
+ Grab the keyboard input focus.
+*/
+PUGL_API PuglStatus
+puglGrabFocus(PuglView* view);
+
+/**
+ Return whether `view` has the keyboard input focus.
*/
PUGL_API bool
-puglGetVisible(PuglView* view);
+puglHasFocus(const PuglView* view);
/**
- Get the current size of the view.
+ Set the clipboard contents.
+
+ This sets the system clipboard contents, which can be retrieved with
+ puglGetClipboard() or pasted into other applications.
+
+ @param view The view.
+ @param type The MIME type of the data, "text/plain" is assumed if `NULL`.
+ @param data The data to copy to the clipboard.
+ @param len The length of data in bytes (including terminator if necessary).
*/
-PUGL_API void
-puglGetSize(PuglView* view, int* width, int* height);
+PUGL_API PuglStatus
+puglSetClipboard(PuglView* view,
+ const char* type,
+ const void* data,
+ size_t len);
/**
- @name Context
- Functions for accessing the drawing context.
- @{
+ Get the clipboard contents.
+
+ This gets the system clipboard contents, which may have been set with
+ puglSetClipboard() or copied from another application.
+
+ @param view The view.
+ @param[out] type Set to the MIME type of the data.
+ @param[out] len Set to the length of the data in bytes.
+ @return The clipboard contents.
*/
+PUGL_API const void*
+puglGetClipboard(PuglView* view, const char** type, size_t* len);
/**
- Get the drawing context.
+ Request user attention.
- For PUGL_GL contexts, this is unused and returns NULL.
- For PUGL_CAIRO contexts, this returns a pointer to a cairo_t.
+ This hints to the system that the window or application requires attention
+ from the user. The exact effect depends on the platform, but is usually
+ something like a flashing task bar entry or bouncing application icon.
*/
-PUGL_API void*
-puglGetContext(PuglView* view);
+PUGL_API PuglStatus
+puglRequestAttention(PuglView* view);
+
+/**
+ Activate a repeating timer event.
+
+ This starts a timer which will send a #PuglEventTimer to `view` every
+ `timeout` seconds. This can be used to perform some action in a view at a
+ regular interval with relatively low frequency. Note that the frequency of
+ timer events may be limited by how often puglUpdate() is called.
+
+ If the given timer already exists, it is replaced.
+ @param view The view to begin seding #PUGL_TIMER events to.
+
+ @param id The identifier for this timer. This is an application-specific ID
+ that should be a low number, typically the value of a constant or `enum`
+ that starts from 0. There is a platform-specific limit to the number of
+ supported timers, and overhead associated with each, so applications should
+ create only a few timers and perform several tasks in one if necessary.
+
+ @param timeout The period, in seconds, of this timer. This is not
+ guaranteed to have a resolution better than 10ms (the maximum timer
+ resolution on Windows) and may be rounded up if it is too short. On X11 and
+ MacOS, a resolution of about 1ms can usually be relied on.
+
+ @return #PUGL_SUCCESS, #PUGL_FAILURE if timers are not supported on this
+ system, or an error code.
+*/
+PUGL_API PuglStatus
+puglStartTimer(PuglView* view, uintptr_t id, double timeout);
/**
- Enter the drawing context.
+ Stop an active timer.
- This must be called before any code that accesses the drawing context,
- including any GL functions. This is only necessary for code that does so
- outside the usual draw callback or handling of an expose event.
+ @param view The view that the timer is set for.
+ @param id The ID previously passed to puglStartTimer().
+ @return #PUGL_SUCCESS, or #PUGL_FAILURE if no such timer was found.
*/
-PUGL_API void
-puglEnterContext(PuglView* view);
+PUGL_API PuglStatus
+puglStopTimer(PuglView* view, uintptr_t id);
/**
- Leave the drawing context.
+ Send an event to a view via the window system.
- This must be called after puglEnterContext and applies the results of the
- drawing code (for example, by swapping buffers).
+ If supported, the event will be delivered to the view via the event loop
+ like other events. Note that this function only works for certain event
+ types, and will return PUGL_UNSUPPORTED_TYPE for events that are not
+ supported.
*/
-PUGL_API void
-puglLeaveContext(PuglView* view, bool flush);
+PUGL_API PuglStatus
+puglSendEvent(PuglView* view, const PuglEvent* event);
/**
@}
*/
+#ifndef PUGL_DISABLE_DEPRECATED
+
/**
- @name Event Handling
+ @}
+ @name Deprecated API
@{
*/
/**
- A function called when an event occurs.
+ A native window handle.
+
+ X11: This is a `Window`.
+
+ MacOS: This is a pointer to an `NSView*`.
+
+ Windows: This is a `HWND`.
*/
-typedef void (*PuglEventFunc)(PuglView* view, const PuglEvent* event);
+typedef uintptr_t PuglNativeWindow;
/**
- Set the function to call when an event occurs.
+ Create a Pugl application and view.
+
+ To create a window, call the various puglInit* functions as necessary, then
+ call puglRealize().
+
+ @deprecated Use puglNewApp() and puglNewView().
+
+ @param pargc Pointer to argument count (currently unused).
+ @param argv Arguments (currently unused).
+ @return A newly created view.
*/
-PUGL_API void
-puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc);
+static inline PUGL_DEPRECATED_BY("puglNewView") PuglView*
+puglInit(const int* pargc, char** argv)
+{
+ (void)pargc;
+ (void)argv;
+
+ return puglNewView(puglNewWorld(PUGL_MODULE, 0));
+}
+
+/**
+ Destroy an app and view created with `puglInit()`.
+
+ @deprecated Use puglFreeApp() and puglFreeView().
+*/
+static inline PUGL_DEPRECATED_BY("puglFreeView") void
+puglDestroy(PuglView* view)
+{
+ PuglWorld* const world = puglGetWorld(view);
+
+ puglFreeView(view);
+ puglFreeWorld(world);
+}
+
+/**
+ Set the window class name before creating a window.
+*/
+static inline PUGL_DEPRECATED_BY("puglSetClassName") void
+puglInitWindowClass(PuglView* view, const char* name)
+{
+ puglSetClassName(puglGetWorld(view), name);
+}
+
+/**
+ Set the window size before creating a window.
+
+ @deprecated Use puglSetFrame().
+*/
+static inline PUGL_DEPRECATED_BY("puglSetFrame") void
+puglInitWindowSize(PuglView* view, int width, int height)
+{
+ PuglRect frame = puglGetFrame(view);
+
+ frame.width = width;
+ frame.height = height;
+
+ puglSetFrame(view, frame);
+}
+
+/**
+ Set the minimum window size before creating a window.
+*/
+static inline PUGL_DEPRECATED_BY("puglSetMinSize") void
+puglInitWindowMinSize(PuglView* view, int width, int height)
+{
+ puglSetMinSize(view, width, height);
+}
+
+/**
+ Set the window aspect ratio range before creating a window.
+
+ The x and y values here represent a ratio of width to height. To set a
+ fixed aspect ratio, set the minimum and maximum values to the same ratio.
+
+ Note that setting different minimum and maximum constraints does not
+ currenty work on MacOS (the minimum is used), so only setting a fixed aspect
+ ratio works properly across all platforms.
+*/
+static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") void
+puglInitWindowAspectRatio(PuglView* view,
+ int minX,
+ int minY,
+ int maxX,
+ int maxY)
+{
+ puglSetAspectRatio(view, minX, minY, maxX, maxY);
+}
+
+/**
+ Set transient parent before creating a window.
+
+ On X11, parent must be a Window.
+ On OSX, parent must be an NSView*.
+*/
+static inline PUGL_DEPRECATED_BY("puglSetTransientFor") void
+puglInitTransientFor(PuglView* view, uintptr_t parent)
+{
+ puglSetTransientFor(view, (PuglNativeWindow)parent);
+}
+
+/**
+ Enable or disable resizing before creating a window.
+
+ @deprecated Use puglSetViewHint() with #PUGL_RESIZABLE.
+*/
+static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
+puglInitResizable(PuglView* view, bool resizable)
+{
+ puglSetViewHint(view, PUGL_RESIZABLE, resizable);
+}
+
+/**
+ Get the current size of the view.
+
+ @deprecated Use puglGetFrame().
+
+*/
+static inline PUGL_DEPRECATED_BY("puglGetFrame") void
+puglGetSize(PuglView* view, int* width, int* height)
+{
+ const PuglRect frame = puglGetFrame(view);
+
+ *width = (int)frame.width;
+ *height = (int)frame.height;
+}
/**
Ignore synthetic repeated key events.
+
+ @deprecated Use puglSetViewHint() with #PUGL_IGNORE_KEY_REPEAT.
*/
-PUGL_API void
-puglIgnoreKeyRepeat(PuglView* view, bool ignore);
+static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
+puglIgnoreKeyRepeat(PuglView* view, bool ignore)
+{
+ puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, ignore);
+}
/**
- Copy selection to clipboard.
+ Set a hint before creating a window.
+
+ @deprecated Use puglSetWindowHint().
*/
-PUGL_API void
-puglCopyToClipboard(PuglView* view, const char* selection, size_t len);
+static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
+puglInitWindowHint(PuglView* view, PuglViewHint hint, int value)
+{
+ puglSetViewHint(view, hint, value);
+}
/**
- Paste selection from clipboard.
+ Set the parent window before creating a window (for embedding).
+
+ @deprecated Use puglSetWindowParent().
*/
-PUGL_API const char*
-puglPasteFromClipboard(PuglView* view, size_t* len);
+static inline PUGL_DEPRECATED_BY("puglSetParentWindow") void
+puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
+{
+ puglSetParentWindow(view, parent);
+}
/**
- Grab the input focus.
+ Set the graphics backend to use.
+
+ @deprecated Use puglSetBackend().
*/
-PUGL_API void
-puglGrabFocus(PuglView* view);
+static inline PUGL_DEPRECATED_BY("puglSetBackend") int
+puglInitBackend(PuglView* view, const PuglBackend* backend)
+{
+ return (int)puglSetBackend(view, backend);
+}
+
+/**
+ Realise a view by creating a corresponding system view or window.
+
+ The view should be fully configured using the above functions before this is
+ called. This function may only be called once per view.
+
+ @deprecated Use puglRealize(), or just show the view.
+*/
+static inline PUGL_DEPRECATED_BY("puglRealize") PuglStatus
+puglCreateWindow(PuglView* view, const char* title)
+{
+ puglSetWindowTitle(view, title);
+ return puglRealize(view);
+}
/**
Block and wait for an event to be ready.
@@ -593,8 +1409,10 @@ puglGrabFocus(PuglView* view);
necessary. This function will block indefinitely if no events are
available, so is not appropriate for use in programs that need to perform
regular updates (e.g. animation).
+
+ @deprecated Use puglPollEvents().
*/
-PUGL_API PuglStatus
+PUGL_API PUGL_DEPRECATED_BY("puglPollEvents") PuglStatus
puglWaitForEvent(PuglView* view);
/**
@@ -603,32 +1421,83 @@ puglWaitForEvent(PuglView* view);
This handles input events as well as rendering, so it should be called
regularly and rapidly enough to keep the UI responsive. This function does
not block if no events are pending.
+
+ @deprecated Use puglDispatchEvents().
*/
-PUGL_API PuglStatus
+PUGL_API PUGL_DEPRECATED_BY("puglDispatchEvents") PuglStatus
puglProcessEvents(PuglView* view);
/**
- @}
+ Poll for events that are ready to be processed.
+
+ This polls for events that are ready for any view in the world, potentially
+ blocking depending on `timeout`.
+
+ @param world The world to poll for events.
+
+ @param timeout Maximum time to wait, in seconds. If zero, the call returns
+ immediately, if negative, the call blocks indefinitely.
+
+ @return #PUGL_SUCCESS if events are read, #PUGL_FAILURE if not, or an error.
+
+ @deprecated Use puglUpdate().
*/
+PUGL_API PUGL_DEPRECATED_BY("puglUpdate") PuglStatus
+puglPollEvents(PuglWorld* world, double timeout);
/**
- Request a redisplay on the next call to puglProcessEvents().
+ Dispatch any pending events to views.
+
+ This processes all pending events, dispatching them to the appropriate
+ views. View event handlers will be called in the scope of this call. This
+ function does not block, if no events are pending then it will return
+ immediately.
+
+ @deprecated Use puglUpdate().
*/
-PUGL_API void
-puglPostRedisplay(PuglView* view);
+PUGL_API PUGL_DEPRECATED_BY("puglUpdate") PuglStatus
+puglDispatchEvents(PuglWorld* world);
/**
- Destroy a GL window.
+ Enter the graphics context.
+
+ Note that, unlike some similar libraries, Pugl automatically enters and
+ leaves the graphics context when required and application should not
+ normally do this. Drawing in Pugl is only allowed during the processing of
+ an expose event.
+
+ However, this can be used to enter the graphics context elsewhere, for
+ example to call any GL functions during setup.
+
+ @param view The view being entered.
+ @param drawing If true, prepare for drawing.
+
+ @deprecated Set up graphics when a #PUGL_CREATE event is received.
*/
-PUGL_API void
-puglDestroy(PuglView* view);
+PUGL_API PUGL_DEPRECATED_BY("PUGL_CREATE") PuglStatus
+puglEnterContext(PuglView* view, bool drawing);
+
+/**
+ Leave the graphics context.
+
+ This must be called after puglEnterContext() with a matching `drawing`
+ parameter.
+
+ @param view The view being left.
+ @param drawing If true, finish drawing, for example by swapping buffers.
+
+ @deprecated Shut down graphics when a #PUGL_DESTROY event is received.
+*/
+PUGL_API PUGL_DEPRECATED_BY("PUGL_DESTROY") PuglStatus
+puglLeaveContext(PuglView* view, bool drawing);
+
+#endif /* PUGL_DISABLE_DEPRECATED */
/**
@}
+ @}
*/
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
+PUGL_END_DECLS
-#endif /* PUGL_H_INCLUDED */
+#endif /* PUGL_PUGL_H */
diff --git a/subprojects/d2tk/pugl/pugl/pugl.hpp b/subprojects/d2tk/pugl/pugl/pugl.hpp
index 7d3ea9e3..73cfe2a6 100644
--- a/subprojects/d2tk/pugl/pugl/pugl.hpp
+++ b/subprojects/d2tk/pugl/pugl/pugl.hpp
@@ -1,5 +1,5 @@
/*
- Copyright 2012-2015 David Robillard <http://drobilla.net>
+ Copyright 2012-2019 David Robillard <http://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
@@ -15,22 +15,35 @@
*/
/**
- @file pugl.hpp C++ API for Pugl, a minimal portable API for OpenGL.
+ @file pugl.hpp Pugl C++ API wrapper.
*/
-#ifndef PUGL_HPP_INCLUDED
-#define PUGL_HPP_INCLUDED
+#ifndef PUGL_PUGL_HPP
+#define PUGL_PUGL_HPP
#include "pugl/pugl.h"
/**
- @defgroup puglmm Puglmm
- C++ API wrapper for Pugl.
+ @defgroup puglxx C++
+
+ C++ API wrapper.
+
+ @ingroup pugl_api
@{
*/
+/**
+ Pugl C++ API namespace.
+*/
namespace pugl {
+/**
+ A drawable region that receives events.
+
+ This is a thin wrapper for a PuglView that contains only a pointer.
+
+ @ingroup puglxx
+*/
class View {
public:
View(int* pargc, char** argv)
@@ -66,8 +79,8 @@ public:
puglInitTransientFor(_view, parent);
}
- virtual void initContextType(PuglContextType type) {
- puglInitContextType(_view, type);
+ virtual void initBackend(const PuglBackend* backend) {
+ puglInitBackend(_view, backend);
}
virtual void createWindow(const char* title) {
@@ -83,8 +96,7 @@ public:
virtual void* getContext() { return puglGetContext(_view); }
virtual void ignoreKeyRepeat(bool ignore) { puglIgnoreKeyRepeat(_view, ignore); }
virtual void grabFocus() { puglGrabFocus(_view); }
- virtual void copyToClipboard(char* selection) { puglCopyToClipboard(_view, selection); }
- virtual const char* pasteFromClipboard() { return puglPasteFromClipboard(_view); }
+ virtual void requestAttention() { puglRequestAttention(_view); }
virtual PuglStatus waitForEvent() { return puglWaitForEvent(_view); }
virtual PuglStatus processEvents() { return puglProcessEvents(_view); }
virtual void postRedisplay() { puglPostRedisplay(_view); }
@@ -105,4 +117,4 @@ private:
@}
*/
-#endif /* PUGL_HPP_INCLUDED */
+#endif /* PUGL_PUGL_HPP */
diff --git a/subprojects/d2tk/pugl/pugl/pugl_cairo.h b/subprojects/d2tk/pugl/pugl/pugl_cairo.h
new file mode 100644
index 00000000..e71072e8
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/pugl_cairo.h
@@ -0,0 +1,49 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 pugl_cairo.h Declaration of Cairo backend accessor.
+*/
+
+#ifndef PUGL_PUGL_CAIRO_H
+#define PUGL_PUGL_CAIRO_H
+
+#include "pugl/pugl.h"
+
+PUGL_BEGIN_DECLS
+
+/**
+ @defgroup cairo Cairo
+ Cairo graphics support.
+ @ingroup pugl_api
+ @{
+*/
+
+/**
+ Cairo graphics backend accessor.
+
+ Pass the return value to puglInitBackend() to draw to a view with Cairo.
+*/
+PUGL_API const PuglBackend*
+puglCairoBackend(void);
+
+/**
+ @}
+*/
+
+PUGL_END_DECLS
+
+#endif // PUGL_PUGL_CAIRO_H
diff --git a/subprojects/d2tk/pugl/pugl/glew.h b/subprojects/d2tk/pugl/pugl/pugl_cairo_backend.h
index 5374406a..3f8cec3d 100644
--- a/subprojects/d2tk/pugl/pugl/glew.h
+++ b/subprojects/d2tk/pugl/pugl/pugl_cairo_backend.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016 David Robillard <http://drobilla.net>
+ Copyright 2012-2019 David Robillard <http://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
@@ -14,19 +14,10 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/**
- @file gl.h Portable header wrapper for glew.h.
+#ifndef PUGL_PUGL_CAIRO_BACKEND_H
+#define PUGL_PUGL_CAIRO_BACKEND_H
- Unfortunately, GL includes vary across platforms so this header allows for
- pure portable programs.
-*/
-
-#ifdef __APPLE__
-# include "OpenGL/glew.h"
-#else
-# ifdef _WIN32
-# include <windows.h> /* Broken Windows GL headers require this */
-# endif
-# include "GL/glew.h"
-#endif
+#warning "This header is deprecated, use pugl/pugl_cairo.h instead."
+#include "pugl/pugl_cairo.h"
+#endif // PUGL_PUGL_CAIRO_BACKEND_H
diff --git a/subprojects/d2tk/pugl/pugl/pugl_gl.h b/subprojects/d2tk/pugl/pugl/pugl_gl.h
new file mode 100644
index 00000000..9c5fa945
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/pugl_gl.h
@@ -0,0 +1,60 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 pugl_gl.h OpenGL-specific API.
+*/
+
+#ifndef PUGL_PUGL_GL_H
+#define PUGL_PUGL_GL_H
+
+#include "pugl/pugl.h"
+
+PUGL_BEGIN_DECLS
+
+/**
+ @defgroup gl OpenGL
+ OpenGL graphics support.
+ @ingroup pugl_api
+ @{
+*/
+
+/**
+ OpenGL extension function.
+*/
+typedef void (*PuglGlFunc)(void);
+
+/**
+ Return the address of an OpenGL extension function.
+*/
+PUGL_API PuglGlFunc
+puglGetProcAddress(const char* name);
+
+/**
+ OpenGL graphics backend.
+
+ Pass the return value to puglSetBackend() to draw to a view with OpenGL.
+*/
+PUGL_API const PuglBackend*
+puglGlBackend(void);
+
+PUGL_END_DECLS
+
+/**
+ @}
+*/
+
+#endif // PUGL_PUGL_GL_H
diff --git a/subprojects/d2tk/pugl/pugl/pugl_gl_backend.h b/subprojects/d2tk/pugl/pugl/pugl_gl_backend.h
new file mode 100644
index 00000000..e1b9a152
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/pugl_gl_backend.h
@@ -0,0 +1,23 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 PUGL_PUGL_GL_BACKEND_H
+#define PUGL_PUGL_GL_BACKEND_H
+
+#warning "This header is deprecated, use pugl/pugl_gl.h instead."
+#include "pugl/pugl_gl.h"
+
+#endif // PUGL_PUGL_GL_BACKEND_H
diff --git a/subprojects/d2tk/pugl/pugl/pugl_internal.h b/subprojects/d2tk/pugl/pugl/pugl_internal.h
deleted file mode 100644
index 5976cd76..00000000
--- a/subprojects/d2tk/pugl/pugl/pugl_internal.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- Copyright 2012-2016 David Robillard <http://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 pugl_internal.h Private platform-independent definitions.
-
- Note this file contains function definitions, so it must be compiled into
- the final binary exactly once. Each platform specific implementation file
- including it once should achieve this.
-
- If you are copying the pugl code into your source tree, the following
- symbols can be defined to tweak pugl behaviour:
-
- PUGL_HAVE_CAIRO: Include Cairo support code.
- PUGL_HAVE_GL: Include OpenGL support code.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "pugl/pugl.h"
-
-typedef struct PuglInternalsImpl PuglInternals;
-
-struct PuglViewImpl {
- PuglHandle handle;
- PuglEventFunc eventFunc;
-
- PuglInternals* impl;
- char* selection;
-
- char* windowClass;
- PuglNativeWindow parent;
- PuglContextType ctx_type;
- uintptr_t transient_parent;
-
- int width;
- int height;
- int min_width;
- int min_height;
- int min_aspect_x;
- int min_aspect_y;
- int max_aspect_x;
- int max_aspect_y;
- bool ignoreKeyRepeat;
- bool redisplay;
- bool resizable;
- bool visible;
-};
-
-PuglInternals* puglInitInternals(void);
-
-PuglView*
-puglInit(int* pargc __attribute__((unused)), char** argv __attribute__((unused)))
-{
- PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
- if (!view) {
- return NULL;
- }
-
- PuglInternals* impl = puglInitInternals();
- if (!impl) {
- return NULL;
- }
-
- view->ctx_type = PUGL_GL;
- view->impl = impl;
- view->width = 640;
- view->height = 480;
-
- return view;
-}
-
-void
-puglInitWindowSize(PuglView* view, int width, int height)
-{
- view->width = width;
- view->height = height;
-}
-
-void
-puglInitWindowMinSize(PuglView* view, int width, int height)
-{
- view->min_width = width;
- view->min_height = height;
-}
-
-void
-puglInitWindowAspectRatio(PuglView* view,
- int min_x,
- int min_y,
- int max_x,
- int max_y)
-{
- view->min_aspect_x = min_x;
- view->min_aspect_y = min_y;
- view->max_aspect_x = max_x;
- view->max_aspect_y = max_y;
-}
-
-void
-puglInitWindowClass(PuglView* view, const char* name)
-{
- const size_t len = strlen(name);
-
- free(view->windowClass);
- view->windowClass = (char*)calloc(1, len + 1);
- memcpy(view->windowClass, name, len);
-}
-
-void
-puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
-{
- view->parent = parent;
-}
-
-void
-puglInitResizable(PuglView* view, bool resizable)
-{
- view->resizable = resizable;
-}
-
-void
-puglInitTransientFor(PuglView* view, uintptr_t parent)
-{
- view->transient_parent = parent;
-}
-
-void
-puglInitContextType(PuglView* view, PuglContextType type)
-{
- view->ctx_type = type;
-}
-
-void
-puglSetHandle(PuglView* view, PuglHandle handle)
-{
- view->handle = handle;
-}
-
-PuglHandle
-puglGetHandle(PuglView* view)
-{
- return view->handle;
-}
-
-bool
-puglGetVisible(PuglView* view)
-{
- return view->visible;
-}
-
-void
-puglGetSize(PuglView* view, int* width, int* height)
-{
- *width = view->width;
- *height = view->height;
-}
-
-void
-puglIgnoreKeyRepeat(PuglView* view, bool ignore)
-{
- view->ignoreKeyRepeat = ignore;
-}
-
-void
-puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc)
-{
- view->eventFunc = eventFunc;
-}
-
-/** Return the code point for buf, or the replacement character on error. */
-static uint32_t
-puglDecodeUTF8(const uint8_t* buf)
-{
-#define FAIL_IF(cond) { if (cond) return 0xFFFD; }
-
- // http://en.wikipedia.org/wiki/UTF-8
-
- if (buf[0] < 0x80) {
- return buf[0];
- } else if (buf[0] < 0xC2) {
- return 0xFFFD;
- } else if (buf[0] < 0xE0) {
- FAIL_IF((buf[1] & 0xC0) != 0x80);
- return (buf[0] << 6) + buf[1] - 0x3080;
- } else if (buf[0] < 0xF0) {
- FAIL_IF((buf[1] & 0xC0) != 0x80);
- FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0);
- FAIL_IF((buf[2] & 0xC0) != 0x80);
- return (buf[0] << 12) + (buf[1] << 6) + buf[2] - 0xE2080;
- } else if (buf[0] < 0xF5) {
- FAIL_IF((buf[1] & 0xC0) != 0x80);
- FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90);
- FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90);
- FAIL_IF((buf[2] & 0xC0) != 0x80);
- FAIL_IF((buf[3] & 0xC0) != 0x80);
- return ((buf[0] << 18) +
- (buf[1] << 12) +
- (buf[2] << 6) +
- buf[3] - 0x3C82080);
- }
- return 0xFFFD;
-}
-
-static void
-puglDispatchEvent(PuglView* view, const PuglEvent* event)
-{
- switch (event->type) {
- case PUGL_NOTHING:
- break;
- case PUGL_CONFIGURE:
- view->width = event->configure.width;
- view->height = event->configure.height;
- puglEnterContext(view);
- view->eventFunc(view, event);
- puglLeaveContext(view, false);
- break;
- case PUGL_EXPOSE:
- if (event->expose.count == 0) {
- puglEnterContext(view);
- view->eventFunc(view, event);
- puglLeaveContext(view, true);
- }
- break;
- default:
- view->eventFunc(view, event);
- }
-}
-
-static void
-puglClearSelection(PuglView* view)
-{
- if(view->selection) {
- free(view->selection);
- view->selection = NULL;
- }
-}
-
-static void
-puglSetSelection(PuglView* view, const char *selection, size_t len)
-{
- puglClearSelection(view);
-
- if(selection) {
- view->selection = (char*)malloc(len + 1);
- if(view->selection) {
- memcpy(view->selection, selection, len);
- view->selection[len] = 0;
- }
- }
-}
-
-static const char*
-puglGetSelection(PuglView* view, size_t* len)
-{
- if(len)
- *len = view->selection ? strlen(view->selection) : 0;
- return view->selection;
-}
diff --git a/subprojects/d2tk/pugl/pugl/pugl_osx.m b/subprojects/d2tk/pugl/pugl/pugl_osx.m
deleted file mode 100644
index 014d553a..00000000
--- a/subprojects/d2tk/pugl/pugl/pugl_osx.m
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- Copyright 2012-2016 David Robillard <http://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 pugl_osx.m OSX/Cocoa Pugl Implementation.
-*/
-
-#include <stdlib.h>
-
-#import <Cocoa/Cocoa.h>
-
-#include "pugl/cairo_gl.h"
-#include "pugl/gl.h"
-#include "pugl/pugl_internal.h"
-
-@class PuglOpenGLView;
-
-struct PuglInternalsImpl {
- NSApplication* app;
- PuglOpenGLView* glview;
- id window;
- NSEvent* nextEvent;
- unsigned mods;
-#ifdef PUGL_HAVE_CAIRO
- cairo_surface_t* surface;
- cairo_t* cr;
- PuglCairoGL cairo_gl;
-#endif
-};
-
-@interface PuglWindow : NSWindow
-{
-@public
- PuglView* puglview;
-}
-
-- (id) initWithContentRect:(NSRect)contentRect
- styleMask:(unsigned int)aStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)flag;
-- (void) setPuglview:(PuglView*)view;
-- (BOOL) windowShouldClose:(id)sender;
-- (BOOL) canBecomeKeyWindow:(id)sender;
-@end
-
-@implementation PuglWindow
-
-- (id)initWithContentRect:(NSRect)contentRect
- styleMask:(unsigned int)aStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)flag
-{
- if (![super initWithContentRect:contentRect
- styleMask:(NSClosableWindowMask |
- NSTitledWindowMask |
- NSResizableWindowMask)
- backing:NSBackingStoreBuffered defer:NO]) {
- return nil;
- }
-
- [self setAcceptsMouseMovedEvents:YES];
- return (PuglWindow*)self;
-}
-
-- (void)setPuglview:(PuglView*)view
-{
- puglview = view;
- [self setContentSize:NSMakeSize(view->width, view->height)];
-}
-
-- (BOOL)windowShouldClose:(id)sender
-{
- const PuglEventClose ev = {
- PUGL_CLOSE,
- puglview,
- 0
- };
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
-
- return YES;
-}
-
-- (BOOL) canBecomeKeyWindow
-{
- return YES;
-}
-
-- (BOOL) canBecomeMainWindow
-{
- return YES;
-}
-
-- (BOOL) canBecomeKeyWindow:(id)sender
-{
- return NO;
-}
-
-@end
-
-@interface PuglOpenGLView : NSOpenGLView
-{
-@public
- PuglView* puglview;
-
- NSTrackingArea* trackingArea;
-}
-
-- (id) initWithFrame:(NSRect)frame;
-- (void) reshape;
-- (void) drawRect:(NSRect)rect;
-- (NSPoint) eventLocation:(NSEvent*)event;
-- (void) mouseEntered:(NSEvent*)event;
-- (void) mouseExited:(NSEvent*)event;
-- (void) mouseMoved:(NSEvent*)event;
-- (void) mouseDragged:(NSEvent*)event;
-- (void) rightMouseDragged:(NSEvent*)event;
-- (void) mouseDown:(NSEvent*)event;
-- (void) mouseUp:(NSEvent*)event;
-- (void) rightMouseDragged:(NSEvent*)event;
-- (void) rightMouseDown:(NSEvent*)event;
-- (void) rightMouseUp:(NSEvent*)event;
-- (void) otherMouseDragged:(NSEvent*)event;
-- (void) otherMouseDown:(NSEvent*)event;
-- (void) otherMouseUp:(NSEvent*)event;
-- (void) scrollWheel:(NSEvent*)event;
-- (void) keyDown:(NSEvent*)event;
-- (void) keyUp:(NSEvent*)event;
-- (void) flagsChanged:(NSEvent*)event;
-
-@end
-
-@implementation PuglOpenGLView
-
-- (id) initWithFrame:(NSRect)frame
-{
- NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
- NSOpenGLPFADoubleBuffer,
- NSOpenGLPFAAccelerated,
- NSOpenGLPFAColorSize, 32,
- NSOpenGLPFADepthSize, 32,
- NSOpenGLPFAMultisample,
- NSOpenGLPFASampleBuffers, 1,
- NSOpenGLPFASamples, 4,
- 0
- };
-
- NSOpenGLPixelFormat* pixelFormat = [
- [NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs];
-
- if (pixelFormat) {
- self = [super initWithFrame:frame pixelFormat:pixelFormat];
- [pixelFormat release];
- } else {
- self = [super initWithFrame:frame];
- }
-
- if (self) {
- [[self openGLContext] makeCurrentContext];
- [self reshape];
- [NSOpenGLContext clearCurrentContext];
- }
- return self;
-}
-
-- (void) reshape
-{
- [[self openGLContext] update];
-
- if (!puglview) {
- return;
- }
-
- const NSRect bounds = [self bounds];
- const PuglEventConfigure ev = {
- PUGL_CONFIGURE,
- puglview,
- 0,
- bounds.origin.x,
- bounds.origin.y,
- bounds.size.width,
- bounds.size.height,
- };
-
-#ifdef PUGL_HAVE_CAIRO
- PuglInternals* impl = puglview->impl;
- if (puglview->ctx_type & PUGL_CAIRO) {
- cairo_surface_destroy(impl->surface);
- cairo_destroy(impl->cr);
- impl->surface = pugl_cairo_gl_create(
- &impl->cairo_gl, ev.width, ev.height, 4);
- impl->cr = cairo_create(impl->surface);
- pugl_cairo_gl_configure(&impl->cairo_gl, ev.width, ev.height);
- }
-#endif
-
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
-}
-
-- (void) drawRect:(NSRect)rect
-{
- const PuglEventExpose ev = {
- PUGL_EXPOSE,
- puglview,
- 0,
- rect.origin.x,
- rect.origin.y,
- rect.size.width,
- rect.size.height,
- 0
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
-
-#ifdef PUGL_HAVE_CAIRO
- if (puglview->ctx_type & PUGL_CAIRO) {
- pugl_cairo_gl_draw(
- &puglview->impl->cairo_gl, puglview->width, puglview->height);
- }
-#endif
-}
-
-- (BOOL) acceptsFirstResponder
-{
- return YES;
-}
-
-static unsigned
-getModifiers(PuglView* view, NSEvent* ev)
-{
- const unsigned modifierFlags = [ev modifierFlags];
-
- unsigned mods = 0;
- mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0;
- mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0;
- mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0;
- mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0;
- return mods;
-}
-
-static PuglKey
-keySymToSpecial(PuglView* view, NSEvent* ev)
-{
- NSString* chars = [ev charactersIgnoringModifiers];
- if([chars length] == 1) {
- switch ([chars characterAtIndex:0]) {
- case NSF1FunctionKey: return PUGL_KEY_F1;
- case NSF2FunctionKey: return PUGL_KEY_F2;
- case NSF3FunctionKey: return PUGL_KEY_F3;
- case NSF4FunctionKey: return PUGL_KEY_F4;
- case NSF5FunctionKey: return PUGL_KEY_F5;
- case NSF6FunctionKey: return PUGL_KEY_F6;
- case NSF7FunctionKey: return PUGL_KEY_F7;
- case NSF8FunctionKey: return PUGL_KEY_F8;
- case NSF9FunctionKey: return PUGL_KEY_F9;
- case NSF10FunctionKey: return PUGL_KEY_F10;
- case NSF11FunctionKey: return PUGL_KEY_F11;
- case NSF12FunctionKey: return PUGL_KEY_F12;
- case NSLeftArrowFunctionKey: return PUGL_KEY_LEFT;
- case NSUpArrowFunctionKey: return PUGL_KEY_UP;
- case NSRightArrowFunctionKey: return PUGL_KEY_RIGHT;
- case NSDownArrowFunctionKey: return PUGL_KEY_DOWN;
- case NSPageUpFunctionKey: return PUGL_KEY_PAGE_UP;
- case NSPageDownFunctionKey: return PUGL_KEY_PAGE_DOWN;
- case NSHomeFunctionKey: return PUGL_KEY_HOME;
- case NSEndFunctionKey: return PUGL_KEY_END;
- case NSInsertFunctionKey: return PUGL_KEY_INSERT;
- /* special keys (SHIFT, CTRL, ALT, SUPER) are handled in [flagsChanged] */
- }
- }
- return (PuglKey)0;
-}
-
--(void)updateTrackingAreas
-{
- if (trackingArea != nil) {
- [self removeTrackingArea:trackingArea];
- [trackingArea release];
- }
-
- const int opts = (NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveAlways);
- trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
- options:opts
- owner:self
- userInfo:nil];
- [self addTrackingArea:trackingArea];
-}
-
-- (NSPoint) eventLocation:(NSEvent*)event
-{
- return [self convertPoint:[event locationInWindow] fromView:nil];
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent
-{
- [self updateTrackingAreas];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent
-{
-}
-
-- (void) mouseMoved:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventMotion ev = {
- PUGL_MOTION_NOTIFY,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(puglview, event),
- 0,
- 1
- };
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
-}
-
-- (void) mouseDragged:(NSEvent*)event
-{
- [self mouseMoved: event];
-}
-
-- (void) rightMouseDragged:(NSEvent*)event
-{
- [self mouseMoved: event];
-}
-
-- (void) otherMouseDragged:(NSEvent*)event
-{
- [self mouseMoved: event];
-}
-
-- (void) mouseDown:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventButton ev = {
- PUGL_BUTTON_PRESS,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(puglview, event),
- [event buttonNumber] + 1
- };
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
-}
-
-- (void) mouseUp:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventButton ev = {
- PUGL_BUTTON_RELEASE,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(puglview, event),
- [event buttonNumber] + 1
- };
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
- [self updateTrackingAreas];
-}
-
-- (void) rightMouseDown:(NSEvent*)event
-{
- [self mouseDown: event];
-}
-
-- (void) rightMouseUp:(NSEvent*)event
-{
- [self mouseUp: event];
-}
-
-- (void) otherMouseDown:(NSEvent*)event
-{
- [self mouseDown: event];
-}
-
-- (void) otherMouseUp:(NSEvent*)event
-{
- [self mouseUp: event];
-}
-
-- (void) scrollWheel:(NSEvent*)event
-{
- [self updateTrackingAreas];
-
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const PuglEventScroll ev = {
- PUGL_SCROLL,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(puglview, event),
- [event deltaX],
- [event deltaY]
- };
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
- [self updateTrackingAreas];
-}
-
-- (void) keyDown:(NSEvent*)event
-{
- if (puglview->ignoreKeyRepeat && [event isARepeat]) {
- return;
- }
-
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const NSString* chars = [event characters];
- const char* str = [chars UTF8String];
- PuglEventKey ev = {
- PUGL_KEY_PRESS,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(puglview, event),
- [event keyCode],
- puglDecodeUTF8((const uint8_t*)str),
- keySymToSpecial(puglview, event),
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- false
- };
- strncpy((char*)ev.utf8, str, 8);
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
-}
-
-- (void) keyUp:(NSEvent*)event
-{
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- const NSString* chars = [event characters];
- const char* str = [chars UTF8String];
- const PuglEventKey ev = {
- PUGL_KEY_RELEASE,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- getModifiers(puglview, event),
- [event keyCode],
- puglDecodeUTF8((const uint8_t*)str),
- keySymToSpecial(puglview, event),
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- false,
- };
- strncpy((char*)ev.utf8, str, 8);
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
-}
-
-- (void) flagsChanged:(NSEvent*)event
-{
- const unsigned mods = getModifiers(puglview, event);
- PuglEventType type = PUGL_NOTHING;
- PuglKey special = 0;
-
- if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) {
- type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_SHIFT;
- } else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) {
- type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_CTRL;
- } else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) {
- type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_ALT;
- } else if ((mods & PUGL_MOD_SUPER) != (puglview->impl->mods & PUGL_MOD_SUPER)) {
- type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- special = PUGL_KEY_SUPER;
- }
-
- if (special != 0) {
- const NSPoint wloc = [self eventLocation:event];
- const NSPoint rloc = [NSEvent mouseLocation];
- PuglEventKey ev = {
- type,
- puglview,
- 0,
- [event timestamp],
- wloc.x,
- puglview->height - wloc.y,
- rloc.x,
- [[NSScreen mainScreen] frame].size.height - rloc.y,
- mods,
- [event keyCode],
- 0,
- special,
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- false
- };
- puglDispatchEvent(puglview, (PuglEvent*)&ev);
- }
-
- puglview->impl->mods = mods;
-}
-
-@end
-
-PuglInternals*
-puglInitInternals(void)
-{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
-}
-
-void
-puglEnterContext(PuglView* view)
-{
- [[view->impl->glview openGLContext] makeCurrentContext];
-}
-
-void
-puglLeaveContext(PuglView* view, bool flush)
-{
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- pugl_cairo_gl_draw(&view->impl->cairo_gl, view->width, view->height);
- }
-#endif
-
- if (flush) {
- //[[view->impl->glview openGLContext] flushBuffer];
- glFlush();
- glSwapAPPLE();
- }
- [NSOpenGLContext clearCurrentContext];
-}
-
-int
-puglCreateWindow(PuglView* view, const char* title)
-{
- PuglInternals* impl = view->impl;
-
- [NSAutoreleasePool new];
- impl->app = [NSApplication sharedApplication];
-
- impl->glview = [PuglOpenGLView new];
- impl->glview->puglview = view;
-
- if (view->transient_parent) {
- NSView* pview = (NSView*)view->transient_parent;
- [pview addSubview:impl->glview];
- [impl->glview setHidden:NO];
- } else {
- NSString* titleString = [[NSString alloc]
- initWithBytes:title
- length:strlen(title)
- encoding:NSUTF8StringEncoding];
-
- id window = [[PuglWindow new] retain];
- [window setPuglview:view];
- [window setTitle:titleString];
- if (view->min_width || view->min_height) {
- [window setContentMinSize:NSMakeSize(view->min_width,
- view->min_height)];
- }
- impl->window = window;
-
- [window setContentView:impl->glview];
- [impl->app activateIgnoringOtherApps:YES];
- [window makeFirstResponder:impl->glview];
- [window makeKeyAndOrderFront:window];
-#if 0
- if (resizable) {
- [impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
- }
-#endif
- }
-
- return 0;
-}
-
-void
-puglShowWindow(PuglView* view)
-{
- [view->impl->window setIsVisible:YES];
- view->visible = true;
-}
-
-void
-puglHideWindow(PuglView* view)
-{
- [view->impl->window setIsVisible:NO];
- view->visible = false;
-}
-
-void
-puglDestroy(PuglView* view)
-{
-#ifdef PUGL_HAVE_CAIRO
- pugl_cairo_gl_free(&view->impl->cairo_gl);
-#endif
- view->impl->glview->puglview = NULL;
- [view->impl->glview removeFromSuperview];
- if (view->impl->window) {
- [view->impl->window close];
- }
- [view->impl->glview release];
- if (view->impl->window) {
- [view->impl->window release];
- }
- puglClearSelection(view);
- free(view->windowClass);
- free(view->impl);
- free(view);
-}
-
-void
-puglCopyToClipboard(PuglView* view, const char* selection, size_t len)
-{
- PuglInternals* const impl = view->impl;
-
- puglSetSelection(view, selection, len);
-
- NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
- if(pasteboard) {
- [pasteboard
- declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil]
- owner:nil];
- [pasteboard
- setString:[NSString stringWithUTF8String:puglGetSelection(view, NULL)]
- forType:NSStringPboardType];
- }
-}
-
-const char*
-puglPasteFromClipboard(PuglView* view, size_t* len)
-{
- PuglInternals* const impl = view->impl;
-
- NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
- if(pasteboard && [ [pasteboard types] containsObject:NSStringPboardType] ) {
- const NSString* mem = [pasteboard stringForType:NSStringPboardType];
- if(mem) {
- const char *utf8 = [mem UTF8String];
- if(utf8)
- puglSetSelection(view, utf8, strlen(utf8));
- }
- }
-
- return puglGetSelection(view, len);
-}
-
-void
-puglGrabFocus(PuglView* view)
-{
- // TODO
-}
-
-PuglStatus
-puglWaitForEvent(PuglView* view)
-{
- /* OSX supposedly has queue: and untilDate: selectors that can be used for
- a blocking non-queueing event check, but if used here cause an
- unsupported selector error at runtime. I have no idea why, so just get
- the event and keep it around until the call to puglProcessEvents. */
- if (!view->impl->nextEvent) {
- view->impl->nextEvent = [view->impl->window
- nextEventMatchingMask: NSAnyEventMask];
- }
-
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglProcessEvents(PuglView* view)
-{
- while (true) {
- // Get the next event, or use the cached one from puglWaitForEvent
- if (!view->impl->nextEvent) {
- view->impl->nextEvent = [view->impl->window
- nextEventMatchingMask: NSAnyEventMask];
- }
-
- if (!view->impl->nextEvent) {
- break; // No events to process, done
- }
-
- // Dispatch event
- [view->impl->app sendEvent: view->impl->nextEvent];
- view->impl->nextEvent = NULL;
- }
-
- return PUGL_SUCCESS;
-}
-
-void
-puglPostRedisplay(PuglView* view)
-{
- //view->redisplay = true; // unused
- [view->impl->glview setNeedsDisplay: YES];
-}
-
-PuglNativeWindow
-puglGetNativeWindow(PuglView* view)
-{
- return (PuglNativeWindow)view->impl->glview;
-}
-
-void*
-puglGetContext(PuglView* view)
-{
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- return view->impl->cr;
- }
-#endif
- return NULL;
-}
diff --git a/subprojects/d2tk/pugl/pugl/pugl_stub.h b/subprojects/d2tk/pugl/pugl/pugl_stub.h
new file mode 100644
index 00000000..da918aac
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/pugl_stub.h
@@ -0,0 +1,103 @@
+/*
+ Copyright 2019 David Robillard <http://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 pugl_stub.h Stub backend functions and accessor declaration.
+*/
+
+#ifndef PUGL_PUGL_STUB_H
+#define PUGL_PUGL_STUB_H
+
+#include "pugl/pugl.h"
+
+PUGL_BEGIN_DECLS
+
+/**
+ @defgroup stub Stub
+
+ Stub graphics backend.
+
+ The stub backend functions do nothing and always
+ return success. These do not make for a usable backend on their own since
+ the platform implementation would fail to create a window, but are useful
+ for other backends to reuse since not all need non-trivial implementations
+ of every backend function.
+
+ @ingroup pugl_api
+ @{
+*/
+
+/**
+ Stub graphics backend.
+
+ This backend just creates a simple native window without setting up any
+ portable graphics API.
+*/
+PUGL_API
+const PuglBackend*
+puglStubBackend(void);
+
+static inline PuglStatus
+puglStubConfigure(PuglView* view)
+{
+ (void)view;
+ return PUGL_SUCCESS;
+}
+
+static inline PuglStatus
+puglStubCreate(PuglView* view)
+{
+ (void)view;
+ return PUGL_SUCCESS;
+}
+
+static inline PuglStatus
+puglStubDestroy(PuglView* view)
+{
+ (void)view;
+ return PUGL_SUCCESS;
+}
+
+static inline PuglStatus
+puglStubEnter(PuglView* view, const PuglEventExpose* expose)
+{
+ (void)view;
+ (void)expose;
+ return PUGL_SUCCESS;
+}
+
+static inline PuglStatus
+puglStubLeave(PuglView* view, const PuglEventExpose* expose)
+{
+ (void)view;
+ (void)expose;
+ return PUGL_SUCCESS;
+}
+
+static inline void*
+puglStubGetContext(PuglView* view)
+{
+ (void)view;
+ return NULL;
+}
+
+/**
+ @}
+*/
+
+PUGL_END_DECLS
+
+#endif // PUGL_PUGL_STUB_H
diff --git a/subprojects/d2tk/pugl/pugl/pugl_stub_backend.h b/subprojects/d2tk/pugl/pugl/pugl_stub_backend.h
new file mode 100644
index 00000000..e5aa5136
--- /dev/null
+++ b/subprojects/d2tk/pugl/pugl/pugl_stub_backend.h
@@ -0,0 +1,23 @@
+/*
+ Copyright 2012-2019 David Robillard <http://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 PUGL_PUGL_STUB_BACKEND_H
+#define PUGL_PUGL_STUB_BACKEND_H
+
+#warning "This header is deprecated, use pugl/pugl_stub.h instead."
+#include "pugl/pugl_stub.h"
+
+#endif // PUGL_PUGL_STUB_BACKEND_H
diff --git a/subprojects/d2tk/pugl/pugl/pugl_win.cpp b/subprojects/d2tk/pugl/pugl/pugl_win.cpp
deleted file mode 100644
index 6468963f..00000000
--- a/subprojects/d2tk/pugl/pugl/pugl_win.cpp
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- Copyright 2012-2015 David Robillard <http://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 pugl_win.cpp Windows/WGL Pugl Implementation.
-*/
-
-#include <windows.h>
-#include <windowsx.h>
-#include <GL/gl.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wctype.h>
-
-#include "pugl/pugl_internal.h"
-
-#ifndef WM_MOUSEWHEEL
-# define WM_MOUSEWHEEL 0x020A
-#endif
-#ifndef WM_MOUSEHWHEEL
-# define WM_MOUSEHWHEEL 0x020E
-#endif
-#ifndef WHEEL_DELTA
-# define WHEEL_DELTA 120
-#endif
-#ifdef _WIN64
-# ifndef GWLP_USERDATA
-# define GWLP_USERDATA (-21)
-# endif
-#else
-# ifndef GWL_USERDATA
-# define GWL_USERDATA (-21)
-# endif
-#endif
-
-#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50)
-
-struct PuglInternalsImpl {
- HWND hwnd;
- HDC hdc;
- HGLRC hglrc;
- WNDCLASS wc;
-};
-
-LRESULT CALLBACK
-wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-
-PuglView*
-puglInit()
-{
- PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
- PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
- if (!view || !impl) {
- return NULL;
- }
-
- view->impl = impl;
- view->width = 640;
- view->height = 480;
-
- return view;
-}
-
-PuglInternals*
-puglInitInternals(void)
-{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
-}
-
-void
-puglEnterContext(PuglView* view)
-{
- PAINTSTRUCT ps;
- BeginPaint(view->impl->hwnd, &ps);
-
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL) {
- wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
- }
-#endif
-}
-
-void
-puglLeaveContext(PuglView* view, bool flush)
-{
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL && flush) {
- glFlush();
- SwapBuffers(view->impl->hdc);
- }
-#endif
-
- PAINTSTRUCT ps;
- EndPaint(view->impl->hwnd, &ps);
-}
-
-int
-puglCreateWindow(PuglView* view, const char* title)
-{
- static const TCHAR* DEFAULT_CLASSNAME = "Pugl";
-
- PuglInternals* impl = view->impl;
-
- if (!title) {
- title = "Window";
- }
-
- WNDCLASSEX wc;
- memset(&wc, 0, sizeof(wc));
- wc.cbSize = sizeof(wc);
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = wndProc;
- wc.hInstance = GetModuleHandle(NULL);
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // TODO: user-specified icon
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
- wc.lpszClassName = view->windowClass ? view->windowClass : DEFAULT_CLASSNAME;
- if (!RegisterClassEx(&wc)) {
- free((void*)impl->wc.lpszClassName);
- free(impl);
- free(view);
- return NULL;
- }
-
- int winFlags = WS_POPUPWINDOW | WS_CAPTION;
- if (view->resizable) {
- winFlags |= WS_SIZEBOX;
- if (view->min_width || view->min_height) {
- // Adjust the minimum window size to accomodate requested view size
- RECT mr = { 0, 0, view->min_width, view->min_height };
- AdjustWindowRectEx(&mr, winFlags, FALSE, WS_EX_TOPMOST);
- view->min_width = mr.right - mr.left;
- view->min_height = mr.bottom - mr.top;
- }
- }
-
- // Adjust the window size to accomodate requested view size
- RECT wr = { 0, 0, view->width, view->height };
- AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);
-
- impl->hwnd = CreateWindowEx(
- WS_EX_TOPMOST,
- wc.lpszClassName, title,
- (view->parent ? WS_CHILD : winFlags),
- CW_USEDEFAULT, CW_USEDEFAULT, wr.right-wr.left, wr.bottom-wr.top,
- (HWND)view->parent, NULL, NULL, NULL);
-
- if (!impl->hwnd) {
- free((void*)impl->wc.lpszClassName);
- free(impl);
- free(view);
- return 1;
- }
-
-#ifdef _WIN64
- SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view);
-#else
- SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view);
-#endif
-
- impl->hdc = GetDC(impl->hwnd);
-
- PIXELFORMATDESCRIPTOR pfd;
- ZeroMemory(&pfd, sizeof(pfd));
- pfd.nSize = sizeof(pfd);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = 24;
- pfd.cDepthBits = 16;
- pfd.iLayerType = PFD_MAIN_PLANE;
-
- int format = ChoosePixelFormat(impl->hdc, &pfd);
- SetPixelFormat(impl->hdc, format, &pfd);
-
- impl->hglrc = wglCreateContext(impl->hdc);
- if (!impl->hglrc) {
- ReleaseDC(impl->hwnd, impl->hdc);
- DestroyWindow(impl->hwnd);
- UnregisterClass(impl->wc.lpszClassName, NULL);
- free((void*)impl->wc.lpszClassName);
- free(impl);
- free(view);
- return NULL;
- }
- wglMakeCurrent(impl->hdc, impl->hglrc);
-
- return 0;
-}
-
-void
-puglShowWindow(PuglView* view)
-{
- PuglInternals* impl = view->impl;
-
- ShowWindow(impl->hwnd, SW_SHOWNORMAL);
- view->visible = true;
-}
-
-void
-puglHideWindow(PuglView* view)
-{
- PuglInternals* impl = view->impl;
-
- ShowWindow(impl->hwnd, SW_HIDE);
- view->visible = false;
-}
-
-void
-puglDestroy(PuglView* view)
-{
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(view->impl->hglrc);
- ReleaseDC(view->impl->hwnd, view->impl->hdc);
- DestroyWindow(view->impl->hwnd);
- UnregisterClass(view->impl->wc.lpszClassName, NULL);
- puglClearSelection(view);
- free(view->windowClass);
- free(view->impl);
- free(view);
-}
-
-static PuglKey
-keySymToSpecial(int sym)
-{
- switch (sym) {
- case VK_F1: return PUGL_KEY_F1;
- case VK_F2: return PUGL_KEY_F2;
- case VK_F3: return PUGL_KEY_F3;
- case VK_F4: return PUGL_KEY_F4;
- case VK_F5: return PUGL_KEY_F5;
- case VK_F6: return PUGL_KEY_F6;
- case VK_F7: return PUGL_KEY_F7;
- case VK_F8: return PUGL_KEY_F8;
- case VK_F9: return PUGL_KEY_F9;
- case VK_F10: return PUGL_KEY_F10;
- case VK_F11: return PUGL_KEY_F11;
- case VK_F12: return PUGL_KEY_F12;
- case VK_LEFT: return PUGL_KEY_LEFT;
- case VK_UP: return PUGL_KEY_UP;
- case VK_RIGHT: return PUGL_KEY_RIGHT;
- case VK_DOWN: return PUGL_KEY_DOWN;
- case VK_PRIOR: return PUGL_KEY_PAGE_UP;
- case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
- case VK_HOME: return PUGL_KEY_HOME;
- case VK_END: return PUGL_KEY_END;
- case VK_INSERT: return PUGL_KEY_INSERT;
- case VK_SHIFT: return PUGL_KEY_SHIFT;
- case VK_CONTROL: return PUGL_KEY_CTRL;
- case VK_MENU: return PUGL_KEY_ALT;
- case VK_LWIN: return PUGL_KEY_SUPER;
- case VK_RWIN: return PUGL_KEY_SUPER;
- }
- return (PuglKey)0;
-}
-
-static unsigned int
-getModifiers()
-{
- unsigned int mods = 0;
- mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0;
- mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0;
- mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0;
- mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0;
- mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0;
- return mods;
-}
-
-static void
-initMouseEvent(PuglEvent* event,
- PuglView* view,
- int button,
- bool press,
- LPARAM lParam)
-{
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ClientToScreen(view->impl->hwnd, &pt);
-
- if (press) {
- SetCapture(view->impl->hwnd);
- } else {
- ReleaseCapture();
- }
-
- event->button.time = GetMessageTime();
- event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE;
- event->button.x = GET_X_LPARAM(lParam);
- event->button.y = GET_Y_LPARAM(lParam);
- event->button.x_root = pt.x;
- event->button.y_root = pt.y;
- event->button.state = getModifiers();
- event->button.button = button;
-}
-
-static void
-initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam, WPARAM wParam)
-{
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ScreenToClient(view->impl->hwnd, &pt);
-
- event->scroll.time = GetMessageTime();
- event->scroll.type = PUGL_SCROLL;
- event->scroll.x = pt.x;
- event->scroll.y = pt.y;
- event->scroll.x_root = GET_X_LPARAM(lParam);
- event->scroll.y_root = GET_Y_LPARAM(lParam);
- event->scroll.state = getModifiers();
- event->scroll.dx = 0;
- event->scroll.dy = 0;
-}
-
-static unsigned int
-utf16_to_code_point(const wchar_t* input, size_t input_size)
-{
- unsigned int code_unit = *input;
- // Equiv. range check between 0xD800 to 0xDBFF inclusive
- if ((code_unit & 0xFC00) == 0xD800) {
- if (input_size < 2) {
- // "Error: is surrogate but input_size too small"
- return 0xFFFD; // replacement character
- }
-
- unsigned int code_unit_2 = *++input;
- // Equiv. range check between 0xDC00 to 0xDFFF inclusive
- if ((code_unit_2 & 0xFC00) == 0xDC00) {
- return (code_unit << 10) + code_unit_2 - 0x35FDC00;
- }
-
- // TODO: push_back(code_unit_2);
- // "Error: Unpaired surrogates."
- return 0xFFFD; // replacement character
- }
- return code_unit;
-}
-
-static void
-initKeyEvent(PuglEvent* event, PuglView* view, bool press, LPARAM lParam)
-{
- POINT rpos = { 0, 0 };
- GetCursorPos(&rpos);
-
- POINT cpos = { rpos.x, rpos.y };
- ScreenToClient(view->impl->hwnd, &rpos);
-
- event->key.type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- event->key.time = GetMessageTime();
- event->key.state = getModifiers();
- event->key.x_root = rpos.x;
- event->key.y_root = rpos.y;
- event->key.x = cpos.x;
- event->key.y = cpos.y;
- event->key.keycode = (lParam & 0xFF0000) >> 16;
- event->key.character = 0;
- event->key.special = static_cast<PuglKey>(0);
- event->key.filter = 0;
-}
-
-static void
-wcharBufToEvent(wchar_t* buf, int n, PuglEvent* event)
-{
- if (n > 0) {
- char* charp = reinterpret_cast<char*>(event->key.utf8);
- if (!WideCharToMultiByte(CP_UTF8, 0, buf, n,
- charp, 8, NULL, NULL)) {
- /* error: could not convert to utf-8,
- GetLastError has details */
- memset(event->key.utf8, 0, 8);
- // replacement character
- event->key.utf8[0] = 0xEF;
- event->key.utf8[1] = 0xBF;
- event->key.utf8[2] = 0xBD;
- }
-
- event->key.character = utf16_to_code_point(buf, n);
- } else {
- // replacement character
- event->key.utf8[0] = 0xEF;
- event->key.utf8[1] = 0xBF;
- event->key.utf8[2] = 0xBD;
- event->key.character = 0xFFFD;
- }
-}
-
-static void
-translateMessageParamsToEvent(LPARAM lParam, WPARAM wParam, PuglEvent* event)
-{
- /* TODO: This is a kludge. Would be nice to use ToUnicode here, but this
- breaks composed keys because it messes with the keyboard state. Not
- sure how to correctly handle this on Windows. */
-
- // This is how I really want to do this, but it breaks composed keys (é,
- // è, ü, ö, and so on) because ToUnicode messes with the keyboard state.
-
- //wchar_t buf[5];
- //BYTE keyboard_state[256];
- //int wcharCount = 0;
- //GetKeyboardState(keyboard_state);
- //wcharCount = ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC),
- // keyboard_state, buf, 4, 0);
- //wcharBufToEvent(buf, wcharCount, event);
-
- // So, since Google refuses to give me a better solution, and if no one
- // else has a better solution, I will make a hack...
- wchar_t buf[5] = { 0, 0, 0, 0, 0 };
- UINT c = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
- buf[0] = c & 0xffff;
- // TODO: This does not take caps lock into account
- // TODO: Dead keys should affect key releases as well
- if (!(event->key.state && PUGL_MOD_SHIFT))
- buf[0] = towlower(buf[0]);
- wcharBufToEvent(buf, 1, event);
- event->key.filter = ((c >> 31) & 0x1);
-}
-
-static void
-translateCharEventToEvent(WPARAM wParam, PuglEvent* event)
-{
- wchar_t buf[2];
- int wcharCount;
- if (wParam & 0xFFFF0000) {
- wcharCount = 2;
- buf[0] = (wParam & 0xFFFF);
- buf[1] = ((wParam >> 16) & 0xFFFF);
- } else {
- wcharCount = 1;
- buf[0] = (wParam & 0xFFFF);
- }
- wcharBufToEvent(buf, wcharCount, event);
-}
-
-static bool
-ignoreKeyEvent(PuglView* view, LPARAM lParam)
-{
- return view->ignoreKeyRepeat && (lParam & (1 << 30));
-}
-
-static LRESULT
-handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
-{
- PuglEvent event;
- void* dummy_ptr = NULL;
- RECT rect;
- MINMAXINFO* mmi;
- POINT pt;
- bool dispatchThisEvent = true;
-
- memset(&event, 0, sizeof(event));
-
- event.any.type = PUGL_NOTHING;
- event.any.view = view;
- if (InSendMessageEx(dummy_ptr)) {
- event.any.flags |= PUGL_IS_SEND_EVENT;
- }
-
- switch (message) {
- case WM_CREATE:
- case WM_SHOWWINDOW:
- case WM_SIZE:
- GetWindowRect(view->impl->hwnd, &rect);
- event.configure.type = PUGL_CONFIGURE;
- event.configure.x = rect.left;
- event.configure.y = rect.top;
- view->width = rect.right - rect.left;
- view->height = rect.bottom - rect.top;
- event.configure.width = view->width;
- event.configure.height = view->height;
- break;
- case WM_GETMINMAXINFO:
- mmi = (MINMAXINFO*)lParam;
- mmi->ptMinTrackSize.x = view->min_width;
- mmi->ptMinTrackSize.y = view->min_height;
- break;
- case WM_PAINT:
- GetUpdateRect(view->impl->hwnd, &rect, false);
- event.expose.type = PUGL_EXPOSE;
- event.expose.x = rect.left;
- event.expose.y = rect.top;
- event.expose.width = rect.right - rect.left;
- event.expose.height = rect.bottom - rect.top;
- event.expose.count = 0;
- break;
- case WM_MOUSEMOVE:
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
- ClientToScreen(view->impl->hwnd, &pt);
-
- event.motion.type = PUGL_MOTION_NOTIFY;
- event.motion.time = GetMessageTime();
- event.motion.x = GET_X_LPARAM(lParam);
- event.motion.y = GET_Y_LPARAM(lParam);
- event.motion.x_root = pt.x;
- event.motion.y_root = pt.y;
- event.motion.state = getModifiers();
- event.motion.is_hint = false;
- break;
- case WM_LBUTTONDOWN:
- initMouseEvent(&event, view, 1, true, lParam);
- break;
- case WM_MBUTTONDOWN:
- initMouseEvent(&event, view, 2, true, lParam);
- break;
- case WM_RBUTTONDOWN:
- initMouseEvent(&event, view, 3, true, lParam);
- break;
- case WM_LBUTTONUP:
- initMouseEvent(&event, view, 1, false, lParam);
- break;
- case WM_MBUTTONUP:
- initMouseEvent(&event, view, 2, false, lParam);
- break;
- case WM_RBUTTONUP:
- initMouseEvent(&event, view, 3, false, lParam);
- break;
- case WM_MOUSEWHEEL:
- initScrollEvent(&event, view, lParam, wParam);
- event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- break;
- case WM_MOUSEHWHEEL:
- initScrollEvent(&event, view, lParam, wParam);
- event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- break;
- case WM_KEYDOWN:
- if (!ignoreKeyEvent(view, lParam)) {
- initKeyEvent(&event, view, true, lParam);
- if (!(event.key.special = keySymToSpecial(wParam))) {
- event.key.type = PUGL_NOTHING;
- }
- }
- break;
- case WM_CHAR:
- if (!ignoreKeyEvent(view, lParam)) {
- initKeyEvent(&event, view, true, lParam);
- translateCharEventToEvent(wParam, &event);
- }
- break;
- case WM_DEADCHAR:
- if (!ignoreKeyEvent(view, lParam)) {
- initKeyEvent(&event, view, true, lParam);
- translateCharEventToEvent(wParam, &event);
- event.key.filter = 1;
- }
- break;
- case WM_KEYUP:
- initKeyEvent(&event, view, false, lParam);
- if (!(event.key.special = keySymToSpecial(wParam))) {
- translateMessageParamsToEvent(lParam, wParam, &event);
- }
- break;
- case WM_QUIT:
- case PUGL_LOCAL_CLOSE_MSG:
- event.close.type = PUGL_CLOSE;
- break;
- default:
- return DefWindowProc(
- view->impl->hwnd, message, wParam, lParam);
- }
-
- puglDispatchEvent(view, &event);
-
- return 0;
-}
-
-void
-puglCopyToClipboard(PuglView* view, const char* selection, size_t len)
-{
- PuglInternals* const impl = view->impl;
-
- puglSetSelection(view, selection, len);
-
- if(OpenClipboard(impl->hwnd)) {
- const int wsize = MultiByteToWideChar(CP_UTF8, 0, selection, len, NULL, 0);
- if(wsize) {
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
- if(mem) {
- wchar_t* wstr = (wchar_t*)GlobalLock(mem);
- if(wstr) {
- MultiByteToWideChar(CP_UTF8, 0, selection, len, wstr, wsize);
- wstr[wsize] = 0;
- GlobalUnlock(mem);
- SetClipboardData(CF_UNICODETEXT, mem);
- }
- else {
- GlobalFree(mem);
- }
- }
- }
- CloseClipboard();
- }
-}
-
-const char*
-puglPasteFromClipboard(PuglView* view, size_t* len)
-{
- PuglInternals* const impl = view->impl;
-
- if(IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(impl->hwnd)) {
- HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
- if(mem) {
- const int wsize = GlobalSize(mem) / sizeof(wchar_t) - 1;
- if(wsize) {
- wchar_t* wstr = (wchar_t*)GlobalLock(mem);
- if(wstr) {
- const int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, wsize, NULL, 0, NULL, NULL);
- if(utf8size) {
- char* utf8 = (char*)malloc(utf8size);
- if(utf8) {
- WideCharToMultiByte(CP_UTF8, 0, wstr, wsize, utf8, utf8size, NULL, NULL);
- puglSetSelection(view, utf8, utf8size);
- free(utf8);
- }
- }
- GlobalUnlock(mem);
- }
- }
- }
- CloseClipboard();
- }
-
- return puglGetSelection(view, len);
-}
-
-void
-puglGrabFocus(PuglView* view)
-{
- // TODO
-}
-
-PuglStatus
-puglWaitForEvent(PuglView* view)
-{
- WaitMessage();
- return PUGL_SUCCESS;
-}
-
-PuglStatus
-puglProcessEvents(PuglView* view)
-{
- MSG msg;
- while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
- TranslateMessage(&msg);
- handleMessage(view, msg.message, msg.wParam, msg.lParam);
- }
-
- if (view->redisplay) {
- InvalidateRect(view->impl->hwnd, NULL, FALSE);
- view->redisplay = false;
- }
-
- return PUGL_SUCCESS;
-}
-
-LRESULT CALLBACK
-wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
-#ifdef _WIN64
- PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-#else
- PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA);
-#endif
-
- switch (message) {
- case WM_CREATE:
- PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
- return 0;
- case WM_CLOSE:
- PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam);
- return 0;
- case WM_DESTROY:
- return 0;
- default:
- if (view && hwnd == view->impl->hwnd) {
- return handleMessage(view, message, wParam, lParam);
- } else {
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- }
-}
-
-void
-puglPostRedisplay(PuglView* view)
-{
- view->redisplay = true;
-}
-
-PuglNativeWindow
-puglGetNativeWindow(PuglView* view)
-{
- return (PuglNativeWindow)view->impl->hwnd;
-}
diff --git a/subprojects/d2tk/pugl/pugl/pugl_x11.c b/subprojects/d2tk/pugl/pugl/pugl_x11.c
deleted file mode 100644
index 5afc880a..00000000
--- a/subprojects/d2tk/pugl/pugl/pugl_x11.c
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- Copyright 2012-2016 David Robillard <http://drobilla.net>
- Copyright 2013 Robin Gareus <robin@gareus.org>
- Copyright 2011-2012 Ben Loftis, Harrison Consoles
-
- 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 pugl_x11.c X11 Pugl Implementation.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-
-#ifdef PUGL_HAVE_GL
-#include <GL/gl.h>
-#include <GL/glx.h>
-#endif
-
-#ifdef PUGL_HAVE_CAIRO
-#include <cairo/cairo.h>
-#include <cairo/cairo-xlib.h>
-#endif
-
-#include "pugl/cairo_gl.h"
-#include "pugl/pugl_internal.h"
-
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef PUGL_HAVE_GL
-
-/** Attributes for double-buffered RGBA. */
-static int attrListDbl[] = {
- GLX_RGBA,
- GLX_DOUBLEBUFFER , True,
- GLX_RED_SIZE , 4,
- GLX_GREEN_SIZE , 4,
- GLX_BLUE_SIZE , 4,
- GLX_DEPTH_SIZE , 8,
- GLX_STENCIL_SIZE , 8,
- /* GLX_SAMPLE_BUFFERS , 1, */
- /* GLX_SAMPLES , 4, */
- None
-};
-
-/** Attributes for single-buffered RGBA. */
-static int attrListSgl[] = {
- GLX_RGBA,
- GLX_DOUBLEBUFFER , False,
- GLX_RED_SIZE , 4,
- GLX_GREEN_SIZE , 4,
- GLX_BLUE_SIZE , 4,
- GLX_DEPTH_SIZE , 8,
- GLX_STENCIL_SIZE , 8,
- /* GLX_SAMPLE_BUFFERS , 1, */
- /* GLX_SAMPLES , 4, */
- None
-};
-
-/** Null-terminated list of attributes in order of preference. */
-static int* attrLists[] = { attrListDbl, attrListSgl, NULL };
-
-#endif // PUGL_HAVE_GL
-
-struct PuglInternalsImpl {
- Display* display;
- int screen;
- Window win;
- XIM xim;
- XIC xic;
-#ifdef PUGL_HAVE_CAIRO
- cairo_surface_t* surface;
- cairo_t* cr;
-#endif
-#ifdef PUGL_HAVE_GL
- GLXContext ctx;
- int doubleBuffered;
-#endif
-#if defined(PUGL_HAVE_CAIRO) && defined(PUGL_HAVE_GL)
- PuglCairoGL cairo_gl;
-#endif
- Atom clipboard;
- Atom utf8_string;
-};
-
-PuglInternals*
-puglInitInternals(void)
-{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
-}
-
-static XVisualInfo*
-getVisual(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- XVisualInfo* vi = NULL;
-
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type & PUGL_GL) {
- for (int* attr = *attrLists; !vi && *attr; ++attr) {
- vi = glXChooseVisual(impl->display, impl->screen, attr);
- }
- }
-#endif
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO) {
- XVisualInfo pat;
- int n;
- pat.screen = impl->screen;
- vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n);
- }
-#endif
-
- return vi;
-}
-
-#ifdef PUGL_HAVE_CAIRO
-static int
-createCairoContext(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
-
- if (impl->cr) {
- cairo_destroy(impl->cr);
- }
-
- impl->cr = cairo_create(impl->surface);
- return cairo_status(impl->cr);
-}
-#endif
-
-static bool
-createContext(PuglView* view, XVisualInfo* vi)
-{
- PuglInternals* const impl = view->impl;
-
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type & PUGL_GL) {
- impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
- glXGetConfig(impl->display, vi, GLX_DOUBLEBUFFER, &impl->doubleBuffered);
- }
-#endif
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO) {
- impl->surface = cairo_xlib_surface_create(
- impl->display, impl->win, vi->visual, view->width, view->height);
- }
-#endif
-#if defined(PUGL_HAVE_GL) && defined(PUGL_HAVE_CAIRO)
- if (view->ctx_type == PUGL_CAIRO_GL) {
- impl->surface = pugl_cairo_gl_create(
- &impl->cairo_gl, view->width, view->height, 4);
- }
-#endif
-
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- if (cairo_surface_status(impl->surface) != CAIRO_STATUS_SUCCESS) {
- fprintf(stderr, "error: failed to create cairo surface\n");
- return false;
- }
-
- if (createCairoContext(view) != CAIRO_STATUS_SUCCESS) {
- cairo_surface_destroy(impl->surface);
- fprintf(stderr, "error: failed to create cairo context\n");
- return false;
- }
- }
-#endif
-
- return true;
-}
-
-static void
-destroyContext(PuglView* view)
-{
-#if defined(PUGL_HAVE_CAIRO) && defined(PUGL_HAVE_GL)
- if (view->ctx_type == PUGL_CAIRO_GL) {
- pugl_cairo_gl_free(&view->impl->cairo_gl);
- }
-#endif
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type & PUGL_GL) {
- glXDestroyContext(view->impl->display, view->impl->ctx);
- }
-#endif
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- cairo_destroy(view->impl->cr);
- cairo_surface_destroy(view->impl->surface);
- }
-#endif
-}
-
-void
-puglEnterContext(PuglView* view)
-{
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type & PUGL_GL) {
- glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
- }
-#endif
-}
-
-void
-puglLeaveContext(PuglView* view, bool flush)
-{
-#ifdef PUGL_HAVE_GL
- if (flush && view->ctx_type & PUGL_GL) {
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO_GL) {
- pugl_cairo_gl_draw(&view->impl->cairo_gl, view->width, view->height);
- }
-#endif
-
- glFlush();
- if (view->impl->doubleBuffered) {
- glXSwapBuffers(view->impl->display, view->impl->win);
- }
- }
-
- glXMakeCurrent(view->impl->display, None, NULL);
-#endif
-}
-
-int
-puglCreateWindow(PuglView* view, const char* title)
-{
- PuglInternals* const impl = view->impl;
-
- impl->display = XOpenDisplay(0);
- impl->screen = DefaultScreen(impl->display);
-
- XVisualInfo* const vi = getVisual(view);
- if (!vi) {
- return 1;
- }
-
- Window xParent = view->parent
- ? (Window)view->parent
- : RootWindow(impl->display, impl->screen);
-
- Colormap cmap = XCreateColormap(
- impl->display, xParent, vi->visual, AllocNone);
-
- impl->clipboard = XInternAtom(impl->display, "CLIPBOARD", 0);
- impl->utf8_string = XInternAtom(impl->display, "UTF8_STRING", 0);
-
- XSetWindowAttributes attr;
- memset(&attr, 0, sizeof(XSetWindowAttributes));
- attr.colormap = cmap;
- attr.event_mask = (ExposureMask | StructureNotifyMask |
- EnterWindowMask | LeaveWindowMask |
- KeyPressMask | KeyReleaseMask |
- ButtonPressMask | ButtonReleaseMask |
- PointerMotionMask | FocusChangeMask);
-
- impl->win = XCreateWindow(
- impl->display, xParent,
- 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
- CWColormap | CWEventMask, &attr);
-
- if (!createContext(view, vi)) {
- XFree(vi);
- return 2;
- }
-
- XSizeHints sizeHints;
- memset(&sizeHints, 0, sizeof(sizeHints));
- if (!view->resizable) {
- sizeHints.flags = PMinSize|PMaxSize;
- sizeHints.min_width = view->width;
- sizeHints.min_height = view->height;
- sizeHints.max_width = view->width;
- sizeHints.max_height = view->height;
- XSetNormalHints(impl->display, impl->win, &sizeHints);
- } else {
- if (view->min_width || view->min_height) {
- sizeHints.flags = PMinSize;
- sizeHints.min_width = view