aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Hanspeter Portner <dev@open-music-kontrollers.ch>2019-08-23 22:02:41 +0200
committerGravatar Hanspeter Portner <dev@open-music-kontrollers.ch>2019-08-23 22:02:41 +0200
commit6ab5c633f53d941118aff72684c174e0db6cce3f (patch)
tree000c2bb33d83f5ff9dbd100e13426657509270ef
parentd04e8f6463406c7062dccb58edf627b242b74720 (diff)
parent3e0e9be4124b949457c35748c16f74e140f38ae4 (diff)
downloadd2tk-6ab5c633f53d941118aff72684c174e0db6cce3f.zip
d2tk-6ab5c633f53d941118aff72684c174e0db6cce3f.tar.gz
d2tk-6ab5c633f53d941118aff72684c174e0db6cce3f.tar.bz2
d2tk-6ab5c633f53d941118aff72684c174e0db6cce3f.tar.xz
Merge commit '3e0e9be4124b949457c35748c16f74e140f38ae4' into pugl-app
-rw-r--r--pugl/.gitlab-ci.yml15
-rw-r--r--pugl/README.md5
-rw-r--r--pugl/doc/footer.html20
-rw-r--r--pugl/doc/header.html47
-rw-r--r--pugl/doc/layout.xml193
-rw-r--r--pugl/doc/mainpage.md42
-rw-r--r--pugl/doc/reference.doxygen.in (renamed from pugl/Doxyfile.in)203
-rw-r--r--pugl/doc/style.css744
-rw-r--r--pugl/pugl/detail/implementation.c263
-rw-r--r--pugl/pugl/detail/implementation.h31
-rw-r--r--pugl/pugl/detail/mac.h9
-rw-r--r--pugl/pugl/detail/mac.m330
-rw-r--r--pugl/pugl/detail/mac_cairo.m8
-rw-r--r--pugl/pugl/detail/mac_gl.m36
-rw-r--r--pugl/pugl/detail/types.h58
-rw-r--r--pugl/pugl/detail/win.c411
-rw-r--r--pugl/pugl/detail/win.h59
-rw-r--r--pugl/pugl/detail/win_cairo.c13
-rw-r--r--pugl/pugl/detail/win_gl.c38
-rw-r--r--pugl/pugl/detail/x11.c566
-rw-r--r--pugl/pugl/detail/x11.h28
-rw-r--r--pugl/pugl/detail/x11_cairo.c4
-rw-r--r--pugl/pugl/detail/x11_gl.c22
-rw-r--r--pugl/pugl/pugl.h619
-rw-r--r--pugl/pugl/pugl.hpp4
-rw-r--r--pugl/test/glad/glad.c1016
-rw-r--r--pugl/test/glad/glad.h1935
-rw-r--r--pugl/test/glad/khrplatform.h290
-rw-r--r--pugl/test/pugl_cairo_test.c74
-rw-r--r--pugl/test/pugl_gl3_test.c395
-rw-r--r--pugl/test/pugl_test.c293
-rw-r--r--pugl/test/shader_utils.h97
-rw-r--r--pugl/test/test_utils.h195
-rw-r--r--pugl/wscript23
34 files changed, 7177 insertions, 909 deletions
diff --git a/pugl/.gitlab-ci.yml b/pugl/.gitlab-ci.yml
index 4fe8cf9..c7d493d 100644
--- a/pugl/.gitlab-ci.yml
+++ b/pugl/.gitlab-ci.yml
@@ -1,5 +1,6 @@
stages:
- build
+ - deploy
.build_template: &build_definition
stage: build
@@ -39,7 +40,10 @@ arm64_rel:
x64_dbg:
<<: *build_definition
image: lv2plugin/debian-x64
- script: python ./waf configure build -dsT --no-coverage
+ script: python ./waf configure build -dsT --no-coverage --docs
+ artifacts:
+ paths:
+ - build/doc
x64_rel:
<<: *build_definition
@@ -102,3 +106,12 @@ win_rel:
script: python ./waf configure build -T --no-coverage
tags:
- windows
+
+pages:
+ stage: deploy
+ script: mv build/doc/html/ public/
+ dependencies:
+ - x64_dbg
+ artifacts:
+ paths:
+ - public
diff --git a/pugl/README.md b/pugl/README.md
index 8169f79..718e690 100644
--- a/pugl/README.md
+++ b/pugl/README.md
@@ -67,4 +67,9 @@ 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.
+Documentation
+-------------
+
+ * [API reference](https://lv2.gitlab.io/pugl/)
+
-- David Robillard <d@drobilla.net>
diff --git a/pugl/doc/footer.html b/pugl/doc/footer.html
new file mode 100644
index 0000000..0dc6919
--- /dev/null
+++ b/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/pugl/doc/header.html b/pugl/doc/header.html
new file mode 100644
index 0000000..07d4076
--- /dev/null
+++ b/pugl/doc/header.html
@@ -0,0 +1,47 @@
+<!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="annotated.html"><span>Data&#160;Structures</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul>
+ </div>
diff --git a/pugl/doc/layout.xml b/pugl/doc/layout.xml
new file mode 100644
index 0000000..f752de1
--- /dev/null
+++ b/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"/>
+ <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>
+ <detaileddescription title=""/>
+ <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/pugl/doc/mainpage.md b/pugl/doc/mainpage.md
new file mode 100644
index 0000000..5ff2781
--- /dev/null
+++ b/pugl/doc/mainpage.md
@@ -0,0 +1,42 @@
+The complete Pugl C API is documented in the [Pugl](@ref pugl) group,
+and the C++ API wrapper in the [Puglmm](@ref puglmm) group.
+
+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 system-level state,
+then creates one or more views to display.
+
+## View creation
+
+Creating a visible view is a multi-step process.
+A new view allocated with #puglNewView does not yet represent a "real" system window.
+To display, it must first have a [backend set](@ref puglSetBackend),
+and be configured by [setting hints](@ref puglSetViewHint)
+and [configuring the frame](@ref frame).
+
+Once the view is configured,
+the corresponding window can be [created](@ref puglCreateWindow)
+and [shown](@ref puglShowWindow).
+
+Note that a view does not necessary correspond to a top-level system window.
+To create a view within another window,
+call #puglSetParentWindow before #puglCreateWindow.
+
+## Interaction
+
+Interaction with the user and system happens via [events](@ref interaction).
+Before creating a window,
+a view must have an [event handler](@ref PuglEventFunc) set with #puglSetEventFunc.
+This handler 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 (drawing).
+
+## Event Loop
+
+Two functions are used to drive the event loop:
+
+ * #puglPollEvents waits for events to become available.
+ * #puglDispatchEvents processes all pending events.
+
+Redrawing is accomplished by calling #puglPostRedisplay,
+which posts an expose event to the queue.
diff --git a/pugl/Doxyfile.in b/pugl/doc/reference.doxygen.in
index b332116..0035bc1 100644
--- a/pugl/Doxyfile.in
+++ b/pugl/doc/reference.doxygen.in
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.13
+# 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.
@@ -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_SRCDIR@/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,7 +827,7 @@ 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 =
@@ -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
@@ -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
@@ -2140,7 +2203,7 @@ HIDE_UNDOC_RELATIONS = YES
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
-# The default value is: YES.
+# The default value is: NO.
HAVE_DOT = NO
@@ -2296,9 +2359,7 @@ DIRECTORY_GRAPH = NO
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
-# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
-# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
-# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.
diff --git a/pugl/doc/style.css b/pugl/doc/style.css
new file mode 100644
index 0000000..fa366af
--- /dev/null
+++ b/pugl/doc/style.css
@@ -0,0 +1,744 @@
+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: "DejaVu Serif",Palatino,serif;
+ text-rendering: optimizeLegibility;
+}
+
+h1, .title, #projectname, h2, h3, h4, h5, h6 {
+ line-height: 1.0125em;
+ color: #444;
+ font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
+ margin: 1em 0 0.5em 0;
+}
+
+h1, .titlearea .header .titlebox, #projectname {
+ font-size: 300%;
+ font-weight: 400;
+ margin-bottom: 0.25em;
+ margin-top: 0;
+}
+
+.header .headertitle .title {
+ font-size: 180%;
+ font-weight: 400;
+ margin: 0.75em 0.25em 0.5em 0;
+}
+
+.ingroups {
+ display: inline;
+}
+.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;
+}
+
+#shortdesc {
+ margin: 0;
+ color: #666;
+ display: inline-block;
+ font-style: italic;
+ padding: 0;
+}
+
+#titlearea {
+ margin: 0.25em auto 0.25em auto;
+ padding: 0;
+ position: relative;
+ clear: both;
+ line-height: 1.0em;
+}
+
+h2 {
+ font-size: 160%;
+ font-weight: 400;
+}
+
+h3 {
+ font-size: 140%;
+ font-weight: 400;
+}
+
+h4 {
+ font-size: 120%;
+ font-weight: 500;
+}
+
+h5, h6 {
+ font-size: 110%;
+ font-weight: 600;
+}
+
+h1 a, h1 a:link, h1 a:visited ,
+h2 a, h2 a:link, h2 a:visited ,
+h3 a, h3 a:link, h3 a:visited ,
+h4 a, h4 a:link, h4 a:visited ,
+h5 a, h5 a:link, h5 a:visited ,
+h6 a, h6 a:link, h6 a:visited {
+ color: #444;
+}
+
+p {
+ margin: 0.5em 0 0.5em 0;
+}
+
+dt {
+ font-weight: 700;
+}
+
+dd {
+ margin-left: 2em;
+}
+
+caption {
+ font-weight: 700;
+}
+
+span.legend {
+ font-size: small;
+ text-align: center;
+}
+
+h3.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;
+}
+
+/* @group Link Styling */
+a {
+ color: #546E00;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #344E00;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindexHL {
+ background-color: #9CAFD4;
+ color: #FFF;
+ border: 1px double #869DCA;
+}
+
+code {
+ color: #444;
+}
+
+/* @end */
+dl.el {
+ margin-left: -1cm;
+}
+
+.fragment {
+ font-family: "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: .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 {
+ padding: 0 0.25em 0 0.25em;
+ max-width: 60em;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+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: "DejaVu Sans Mono",monospace,fixed;
+}
+
+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;
+}
+
+/* @group Code Colorization */
+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;
+}
+
+/* @end */
+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 1em;
+}
+
+#footer {
+ bottom: 0;
+ clear: both;
+ font-size: x-small;
+ margin: 2em 0 0;
+ padding: 0 1em 1em 1em;
+ vertical-align: top;
+ color: #888;
+}
+
+/* @group Member Descriptions */
+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: "DejaVu Sans Mono",monospace,fixed;
+}
+
+.memItemLeft,.memTemplItemLeft {
+ white-space: nowrap;
+ padding-left: 2em;
+ padding-right: 1em;
+}
+
+.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;
+}
+
+/* @end */
+/* @group Member Details */
+/* Styles for detailed member documentation */
+.memtemplate {
+ color: #888;
+ font-style: italic;
+ font-family: "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.25em 0.5em 0.25em 0.5em;
+ margin: 0 0 1em 0;
+ border-radius: 6px;
+ border: 1px solid #DDD;
+}
+
+.memproto {
+ font-size: 110%;
+ font-weight: 400;
+ line-height: 1em;
+ color: #000;
+}
+
+.memproto .paramname {
+ font-style: normal;
+}
+
+.memdoc {
+ padding: 0 0.25em 0 0.25em;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ color: #666;
+ padding-right: 0.5em;
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #111;
+ white-space: nowrap;
+ font-family: "DejaVu Sans Mono",monospace,fixed;
+ font-style: italic;
+ padding-right: 0.5em;
+}
+
+.fieldname {
+ color: #000;
+}
+
+.fieldtable {
+ padding-top: 0.25em;
+ border-top: 1px dashed #DDD;
+}
+
+.fieldtable tbody tr:first-child {
+ display: none;
+}
+
+td.fieldname {
+ padding: 0 0.5em 0 0.25em;
+ vertical-align: top;
+ font-family: "DejaVu Sans Mono",monospace,fixed;
+}
+
+td.fieldtype {
+ color: #666;
+ padding: 0 0.5em 0 0;
+ vertical-align: top;
+ font-family: "DejaVu Sans Mono",monospace,fixed;
+}
+
+td.fielddoc p {
+ margin: 0;
+ vertical-align: top;
+ padding: 0 0.5em 0 0;
+}
+
+p.reference {
+ font-size: x-small;
+ font-style: italic;
+}
+
+/* @end */
+/* @group Directory (tree) */
+/* for the tree view */
+.ftvtree {
+ font-family: sans-serif;
+ margin: 0;
+}
+
+/* these are for tree view when used as main index */
+.directory {
+ font-size: small;
+ 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",Helvetica,Arial,sans-serif;
+ font-weight: 400;
+ padding-right: 1em;
+}
+
+td.entry .arrow {
+ display: none;
+}
+
+td.entry b {
+ font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
+ font-weight: 400;
+ font-size: 130%;
+}
+
+/* these are for tree view when not used as main index */
+.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%;
+}
+
+/* @end */
+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",Helvetica,Arial,sans-serif;
+ margin: 0;
+ color: #FFF; /* Hide separator bars */
+ border-bottom: 1px solid #DDD;
+ padding: 0.25em 0;
+}
+
+div.summary a {
+ white-space: nowrap;
+}
+
+/* Metadata box (right aligned next to title) */
+
+#metabox {
+ display: inline-block;
+ font-size: x-small;
+ margin: 0 0 0.25em 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+ color: #666;
+ font-style: italic;
+ padding: 0 1em;
+}
+
+#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: "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;
+ border-bottom: 1px solid #DDD;
+ font-size: small;
+ font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
+ margin: 0;
+}
+
+th {
+ text-align: left;
+ font-size: 110%;
+ font-weight: 500;
+}
+
+.mlabel {
+ padding: 0.125em;
+}
+
+#navrow1 {
+ /* Disable menu from Doxygen 1.8.15, it is faked in the template */
+ display: none;
+}
+
+/* tabs*/
+
+.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;
+ font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
+ text-decoration: none;
+ outline: none;
+}
+
+.tabs3 .tablist a {
+ padding: 0 10px;
+}
+
+.tablist li.current a {
+ color: #222;
+}
+
+span.icon {
+ display: none;
+}
diff --git a/pugl/pugl/detail/implementation.c b/pugl/pugl/detail/implementation.c
index 7eeba01..f1fd57a 100644
--- a/pugl/pugl/detail/implementation.c
+++ b/pugl/pugl/detail/implementation.c
@@ -25,144 +25,154 @@
#include <stdlib.h>
#include <string.h>
-static PuglHints
-puglDefaultHints(void)
+void
+puglSetString(char** dest, const char* string)
{
- static const PuglHints hints = {
- 2, 0, 4, 4, 4, 4, 24, 8, 0, true, true, false, false
- };
- return hints;
+ const size_t len = strlen(string);
+
+ *dest = (char*)realloc(*dest, len + 1);
+ strncpy(*dest, string, len + 1);
}
-PuglView*
-puglInit(int* PUGL_UNUSED(pargc), char** PUGL_UNUSED(argv))
+void
+puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len)
{
- PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
- if (!view) {
- return NULL;
+ 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;
}
+}
- PuglInternals* impl = puglInitInternals();
- if (!impl) {
- free(view);
+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_FALSE;
+ hints[PUGL_SWAP_INTERVAL] = 0;
+ hints[PUGL_RESIZABLE] = PUGL_FALSE;
+ hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE;
+}
+
+PuglWorld*
+puglNewWorld(void)
+{
+ PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld));
+ if (!world || !(world->impl = puglInitWorldInternals())) {
+ free(world);
return NULL;
}
- view->hints = puglDefaultHints();
- view->impl = impl;
- view->width = 640;
- view->height = 480;
- view->start_time = puglGetTime(view);
+ world->startTime = puglGetTime(world);
+ puglSetString(&world->className, "Pugl");
- return view;
+ return world;
}
void
-puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value)
+puglFreeWorld(PuglWorld* const world)
{
- switch (hint) {
- case PUGL_USE_COMPAT_PROFILE:
- view->hints.use_compat_profile = value;
- break;
- case PUGL_CONTEXT_VERSION_MAJOR:
- view->hints.context_version_major = value;
- break;
- case PUGL_CONTEXT_VERSION_MINOR:
- view->hints.context_version_minor = value;
- break;
- case PUGL_RED_BITS:
- view->hints.red_bits = value;
- break;
- case PUGL_GREEN_BITS:
- view->hints.green_bits = value;
- break;
- case PUGL_BLUE_BITS:
- view->hints.blue_bits = value;
- break;
- case PUGL_ALPHA_BITS:
- view->hints.alpha_bits = value;
- break;
- case PUGL_DEPTH_BITS:
- view->hints.depth_bits = value;
- break;
- case PUGL_STENCIL_BITS:
- view->hints.stencil_bits = value;
- break;
- case PUGL_SAMPLES:
- view->hints.samples = value;
- break;
- case PUGL_DOUBLE_BUFFER:
- view->hints.double_buffer = value;
- break;
- case PUGL_RESIZABLE:
- view->hints.resizable = value;
- break;
- case PUGL_IGNORE_KEY_REPEAT:
- view->hints.ignoreKeyRepeat = value;
- break;
- }
+ puglFreeWorldInternals(world);
+ free(world->className);
+ free(world->views);
+ free(world);
}
-void
-puglInitWindowSize(PuglView* view, int width, int height)
+PuglStatus
+puglSetClassName(PuglWorld* const world, const char* const name)
{
- view->width = width;
- view->height = height;
+ puglSetString(&world->className, name);
+ return PUGL_SUCCESS;
}
-void
-puglInitWindowMinSize(PuglView* view, int width, int height)
+PuglView*
+puglNewView(PuglWorld* const world)
{
- view->min_width = width;
- view->min_height = height;
-}
+ PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
+ if (!view || !(view->impl = puglInitViewInternals())) {
+ free(view);
+ return NULL;
+ }
-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;
+ 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
-puglInitWindowClass(PuglView* view, const char* name)
+puglFreeView(PuglView* view)
{
- const size_t len = strlen(name);
+ // 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->windowClass);
- view->windowClass = (char*)calloc(1, len + 1);
- memcpy(view->windowClass, name, len);
+ free(view->clipboard.data);
+ puglFreeViewInternals(view);
+ free(view);
}
-void
-puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
+PuglWorld*
+puglGetWorld(PuglView* view)
{
- view->parent = parent;
+ return view->world;
}
-void
-puglInitResizable(PuglView* view, bool resizable)
+PuglStatus
+puglSetViewHint(PuglView* view, PuglViewHint hint, int value)
{
- view->hints.resizable = resizable;
+ if (hint < PUGL_NUM_WINDOW_HINTS) {
+ view->hints[hint] = value;
+ }
+
+ return PUGL_SUCCESS;
}
-void
-puglInitTransientFor(PuglView* view, uintptr_t parent)
+PuglStatus
+puglSetParentWindow(PuglView* view, PuglNativeWindow parent)
{
- view->transient_parent = parent;
+ view->parent = parent;
+ return PUGL_SUCCESS;
}
-int
-puglInitBackend(PuglView* view, const PuglBackend* backend)
+PuglStatus
+puglSetBackend(PuglView* view, const PuglBackend* backend)
{
view->backend = backend;
- return 0;
+ return PUGL_SUCCESS;
}
void
@@ -183,11 +193,10 @@ puglGetVisible(PuglView* view)
return view->visible;
}
-void
-puglGetSize(PuglView* view, int* width, int* height)
+PuglRect
+puglGetFrame(const PuglView* view)
{
- *width = view->width;
- *height = view->height;
+ return view->frame;
}
void*
@@ -196,28 +205,25 @@ puglGetContext(PuglView* view)
return view->backend->getContext(view);
}
-void
+PuglStatus
puglEnterContext(PuglView* view, bool drawing)
{
view->backend->enter(view, drawing);
+ return PUGL_SUCCESS;
}
-void
+PuglStatus
puglLeaveContext(PuglView* view, bool drawing)
{
view->backend->leave(view, drawing);
+ return PUGL_SUCCESS;
}
-void
-puglIgnoreKeyRepeat(PuglView* view, bool ignore)
-{
- puglInitWindowHint(view, PUGL_IGNORE_KEY_REPEAT, ignore);
-}
-
-void
+PuglStatus
puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc)
{
view->eventFunc = eventFunc;
+ return PUGL_SUCCESS;
}
/** Return the code point for buf, or the replacement character on error. */
@@ -261,8 +267,6 @@ puglDispatchEvent(PuglView* view, const PuglEvent* event)
case PUGL_NOTHING:
break;
case PUGL_CONFIGURE:
- view->width = (int)event->configure.width;
- view->height = (int)event->configure.height;
puglEnterContext(view, false);
view->eventFunc(view, event);
puglLeaveContext(view, false);
@@ -278,3 +282,34 @@ puglDispatchEvent(PuglView* view, const PuglEvent* event)
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_ERR_UNSUPPORTED_TYPE;
+ }
+
+ puglSetBlob(&view->clipboard, data, len);
+ return PUGL_SUCCESS;
+}
+
diff --git a/pugl/pugl/detail/implementation.h b/pugl/pugl/detail/implementation.h
index 50f54f5..874e7e1 100644
--- a/pugl/pugl/detail/implementation.h
+++ b/pugl/pugl/detail/implementation.h
@@ -24,14 +24,30 @@
#include "pugl/detail/types.h"
#include "pugl/pugl.h"
+#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
-/** Allocate and initialise internals (implemented once per platform) */
-PuglInternals* puglInitInternals(void);
+/** Set `blob` to `data` with length `len`, reallocating if necessary. */
+void puglSetBlob(PuglBlob* blob, 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(void);
+
+/** 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);
@@ -39,6 +55,17 @@ uint32_t puglDecodeUTF8(const uint8_t* buf);
/** Dispatch `event` to `view`, optimising configure/expose if possible. */
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);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/pugl/pugl/detail/mac.h b/pugl/pugl/detail/mac.h
index 9a5997d..754c346 100644
--- a/pugl/pugl/detail/mac.h
+++ b/pugl/pugl/detail/mac.h
@@ -33,9 +33,10 @@
NSMutableAttributedString* markedText;
NSTimer* timer;
NSTimer* urgentTimer;
+ bool reshaped;
}
-- (void) dispatchConfigure:(NSRect)bounds;
+- (void) setReshaped;
@end
@@ -49,11 +50,15 @@
@end
+struct PuglWorldInternalsImpl {
+ NSApplication* app;
+ NSAutoreleasePool* autoreleasePool;
+};
+
struct PuglInternalsImpl {
NSApplication* app;
PuglWrapperView* wrapperView;
NSView* drawView;
id window;
- NSEvent* nextEvent;
uint32_t mods;
};
diff --git a/pugl/pugl/detail/mac.m b/pugl/pugl/detail/mac.m
index b1bf4fd..9f68919 100644
--- a/pugl/pugl/detail/mac.m
+++ b/pugl/pugl/detail/mac.m
@@ -31,6 +31,31 @@
#include <stdlib.h>
+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
@@ -52,7 +77,7 @@
- (void)setPuglview:(PuglView*)view
{
puglview = view;
- [self setContentSize:NSMakeSize(view->width, view->height)];
+ [self setContentSize:NSMakeSize(view->frame.width, view->frame.height)];
}
- (BOOL) canBecomeKeyWindow
@@ -79,6 +104,22 @@
- (void) drawRect:(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;
+ }
+
const PuglEventExpose ev = {
PUGL_EXPOSE,
0,
@@ -102,18 +143,9 @@
return YES;
}
-- (void) dispatchConfigure:(NSRect)bounds
+- (void) setReshaped
{
- const PuglEventConfigure ev = {
- PUGL_CONFIGURE,
- 0,
- bounds.origin.x,
- bounds.origin.y,
- bounds.size.width,
- bounds.size.height,
- };
-
- puglDispatchEvent(puglview, (const PuglEvent*)&ev);
+ reshaped = true;
}
static uint32_t
@@ -330,7 +362,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
- (void) keyDown:(NSEvent*)event
{
- if (puglview->hints.ignoreKeyRepeat && [event isARepeat]) {
+ if (puglview->hints[PUGL_IGNORE_KEY_REPEAT] && [event isARepeat]) {
return;
}
@@ -566,7 +598,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
- (void) urgentTick
{
- [NSApp requestUserAttention:NSInformationalRequest];
+ [puglview->world->impl->app requestUserAttention:NSInformationalRequest];
}
- (void) viewDidEndLiveResize
@@ -608,6 +640,13 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
return YES;
}
+- (void) windowDidMove:(NSNotification*)notification
+{
+ (void)notification;
+
+ updateViewRect(window->puglview);
+}
+
- (void) windowDidBecomeKey:(NSNotification*)notification
{
(void)notification;
@@ -636,8 +675,27 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
@end
+PuglWorldInternals*
+puglInitWorldInternals(void)
+{
+ 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);
+}
+
PuglInternals*
-puglInitInternals(void)
+puglInitViewInternals(void)
{
return (PuglInternals*)calloc(1, sizeof(PuglInternals));
}
@@ -655,24 +713,22 @@ puglConstraint(id item, NSLayoutAttribute attribute, float constant)
constant: constant];
}
-int
+PuglStatus
puglCreateWindow(PuglView* view, const char* title)
{
PuglInternals* impl = view->impl;
- [NSAutoreleasePool new];
- impl->app = [NSApplication sharedApplication];
-
// Create wrapper view to handle input
impl->wrapperView = [PuglWrapperView alloc];
impl->wrapperView->puglview = view;
impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init];
[impl->wrapperView setAutoresizesSubviews:YES];
- [impl->wrapperView initWithFrame:NSMakeRect(0, 0, view->width, view->height)];
+ [impl->wrapperView initWithFrame:
+ NSMakeRect(0, 0, view->frame.width, view->frame.height)];
[impl->wrapperView addConstraint:
- puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, view->min_width)];
+ puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, view->minWidth)];
[impl->wrapperView addConstraint:
- puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, view->min_height)];
+ puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, view->minHeight)];
// Create draw view to be rendered to
int st = 0;
@@ -696,11 +752,15 @@ puglCreateWindow(PuglView* view, const char* title)
initWithBytes:title
length:strlen(title)
encoding:NSUTF8StringEncoding];
- NSRect frame = NSMakeRect(0, 0, view->min_width, view->min_height);
+
+ const NSRect frame = rectToScreen(
+ NSMakeRect(view->frame.x, view->frame.y,
+ view->minWidth, view->minHeight));
+
unsigned style = (NSClosableWindowMask |
NSTitledWindowMask |
NSMiniaturizableWindowMask );
- if (view->hints.resizable) {
+ if (view->hints[PUGL_RESIZABLE]) {
style |= NSResizableWindowMask;
}
@@ -712,22 +772,23 @@ puglCreateWindow(PuglView* view, const char* title)
] retain];
[window setPuglview:view];
[window setTitle:titleString];
- if (view->min_width || view->min_height) {
- [window setContentMinSize:NSMakeSize(view->min_width,
- view->min_height)];
+ if (view->minWidth || view->minHeight) {
+ [window setContentMinSize:NSMakeSize(view->minWidth,
+ view->minHeight)];
}
impl->window = window;
+ puglSetWindowTitle(view, title);
((NSWindow*)window).delegate = [[PuglWindowDelegate alloc]
initWithPuglWindow:window];
- if (view->min_aspect_x && view->min_aspect_y) {
- [window setContentAspectRatio:NSMakeSize(view->min_aspect_x,
- view->min_aspect_y)];
+ if (view->minAspectX && view->minAspectY) {
+ [window setContentAspectRatio:NSMakeSize(view->minAspectX,
+ view->minAspectY)];
}
[window setContentView:impl->wrapperView];
- [impl->app activateIgnoringOtherApps:YES];
+ [view->world->impl->app activateIgnoringOtherApps:YES];
[window makeFirstResponder:impl->wrapperView];
[window makeKeyAndOrderFront:window];
}
@@ -737,22 +798,25 @@ puglCreateWindow(PuglView* view, const char* title)
return 0;
}
-void
+PuglStatus
puglShowWindow(PuglView* view)
{
[view->impl->window setIsVisible:YES];
+ updateViewRect(view);
view->visible = true;
+ return PUGL_SUCCESS;
}
-void
+PuglStatus
puglHideWindow(PuglView* view)
{
[view->impl->window setIsVisible:NO];
view->visible = false;
+ return PUGL_SUCCESS;
}
void
-puglDestroy(PuglView* view)
+puglFreeViewInternals(PuglView* view)
{
view->backend->destroy(view);
[view->impl->wrapperView removeFromSuperview];
@@ -764,22 +828,33 @@ puglDestroy(PuglView* view)
if (view->impl->window) {
[view->impl->window release];
}
- free(view->windowClass);
free(view->impl);
- free(view);
}
-void
+PuglStatus
puglGrabFocus(PuglView* view)
{
- [view->impl->window makeKeyWindow];
+ NSWindow* window = [view->impl->wrapperView window];
+
+ [window makeKeyWindow];
+ [window makeFirstResponder:view->impl->wrapperView];
+ return PUGL_SUCCESS;
}
-void
+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]) {
- [NSApp requestUserAttention:NSInformationalRequest];
+ [view->world->impl->app requestUserAttention:NSInformationalRequest];
view->impl->wrapperView->urgentTimer =
[NSTimer scheduledTimerWithTimeInterval:2.0
target:view->impl->wrapperView
@@ -787,43 +862,57 @@ puglRequestAttention(PuglView* view)
userInfo:nil
repeats:YES];
}
+
+ return PUGL_SUCCESS;
}
PuglStatus
-puglWaitForEvent(PuglView* view)
+puglPollEvents(PuglWorld* world, const double timeout)
{
+ NSDate* date = ((timeout < 0) ? [NSDate distantFuture] :
+ (timeout == 0) ? nil :
+ [NSDate dateWithTimeIntervalSinceNow:timeout]);
+
/* Note that dequeue:NO is broken (it blocks forever even when events are
- pending), so we work around this by dequeueing the event here and
- storing it in view->impl->nextEvent for later processing. */
- if (!view->impl->nextEvent) {
- view->impl->nextEvent =
- [view->impl->window nextEventMatchingMask:NSAnyEventMask];
- }
+ pending), so we work around this by dequeueing the event then posting it
+ back to the front of the queue. */
+ NSEvent* event = [world->impl->app
+ nextEventMatchingMask:NSAnyEventMask
+ untilDate:date
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+
+ [world->impl->app postEvent:event atStart:true];
return PUGL_SUCCESS;
}
PuglStatus
-puglProcessEvents(PuglView* view)
+puglWaitForEvent(PuglView* view)
{
- if (view->impl->nextEvent) {
- // Process event that was dequeued earier by puglWaitForEvent
- [view->impl->app sendEvent: view->impl->nextEvent];
- view->impl->nextEvent = NULL;
- }
+ return puglPollEvents(view->world, -1.0);
+}
- // Process all pending events
+PUGL_API PuglStatus
+puglDispatchEvents(PuglWorld* world)
+{
for (NSEvent* ev = NULL;
- (ev = [view->impl->window nextEventMatchingMask:NSAnyEventMask
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue:YES]);) {
- [view->impl->app sendEvent: ev];
+ (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES]);) {
+ [world->impl->app sendEvent: ev];
}
return PUGL_SUCCESS;
}
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ return puglDispatchEvents(view->world);
+}
+
PuglGlFunc
puglGetProcAddress(const char *name)
{
@@ -842,15 +931,16 @@ puglGetProcAddress(const char *name)
}
double
-puglGetTime(PuglView* view)
+puglGetTime(const PuglWorld* world)
{
- return (mach_absolute_time() / 1e9) - view->start_time;
+ return (mach_absolute_time() / 1e9) - world->startTime;
}
-void
+PuglStatus
puglPostRedisplay(PuglView* view)
{
[view->impl->wrapperView setNeedsDisplay: YES];
+ return PUGL_SUCCESS;
}
PuglNativeWindow
@@ -858,3 +948,119 @@ puglGetNativeWindow(PuglView* view)
{
return (PuglNativeWindow)view->impl->wrapperView;
}
+
+PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title)
+{
+ puglSetString(&view->title, title);
+
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:title
+ length:strlen(title)
+ encoding:NSUTF8StringEncoding];
+
+ if (view->impl->window) {
+ [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;
+ }
+
+ [pasteboard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil]
+ owner:nil];
+
+ [pasteboard setString:[NSString stringWithUTF8String:str]
+ forType:NSStringPboardType];
+
+ return PUGL_SUCCESS;
+}
diff --git a/pugl/pugl/detail/mac_cairo.m b/pugl/pugl/detail/mac_cairo.m
index b0a8db5..f47e42e 100644
--- a/pugl/pugl/detail/mac_cairo.m
+++ b/pugl/pugl/detail/mac_cairo.m
@@ -50,7 +50,7 @@
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
[super resizeWithOldSuperviewSize:oldSize];
- [wrapper dispatchConfigure:[self bounds]];
+ [wrapper setReshaped];
}
@end
@@ -68,8 +68,8 @@ puglMacCairoCreate(PuglView* view)
PuglCairoView* drawView = [PuglCairoView alloc];
drawView->puglview = view;
- [drawView initWithFrame:NSMakeRect(0, 0, view->width, view->height)];
- if (view->hints.resizable) {
+ [drawView initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)];
+ if (view->hints[PUGL_RESIZABLE]) {
[drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
} else {
[drawView setAutoresizingMask:NSViewNotSizable];
@@ -105,7 +105,7 @@ puglMacCairoEnter(PuglView* view, bool drawing)
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
drawView->surface = cairo_quartz_surface_create_for_cg_context(
- context, view->width, view->height);
+ context, view->frame.width, view->frame.height);
drawView->cr = cairo_create(drawView->surface);
diff --git a/pugl/pugl/detail/mac_gl.m b/pugl/pugl/detail/mac_gl.m
index 4a6e39a..61c0193 100644
--- a/pugl/pugl/detail/mac_gl.m
+++ b/pugl/pugl/detail/mac_gl.m
@@ -40,12 +40,14 @@ typedef NSUInteger NSWindowStyleMask;
- (id) initWithFrame:(NSRect)frame
{
- const int major = puglview->hints.context_version_major;
- const int profile = ((puglview->hints.use_compat_profile || major < 3)
- ? NSOpenGLProfileVersionLegacy
- : puglview->hints.context_version_major >= 4
- ? NSOpenGLProfileVersion4_1Core
- : NSOpenGLProfileVersion3_2Core);
+ const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE];
+ const int samples = puglview->hints[PUGL_SAMPLES];
+ const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR];
+ const int profile = ((compat || major < 3)
+ ? NSOpenGLProfileVersionLegacy
+ : (major >= 4
+ ? NSOpenGLProfileVersion4_1Core
+ : NSOpenGLProfileVersion3_2Core));
NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
NSOpenGLPFADoubleBuffer,
@@ -53,9 +55,9 @@ typedef NSUInteger NSWindowStyleMask;
NSOpenGLPFAOpenGLProfile, profile,
NSOpenGLPFAColorSize, 32,
NSOpenGLPFADepthSize, 32,
- NSOpenGLPFAMultisample, puglview->hints.samples ? 1 : 0,
- NSOpenGLPFASampleBuffers, puglview->hints.samples ? 1 : 0,
- NSOpenGLPFASamples, puglview->hints.samples,
+ NSOpenGLPFAMultisample, samples ? 1 : 0,
+ NSOpenGLPFASampleBuffers, samples ? 1 : 0,
+ NSOpenGLPFASamples, samples,
0};
NSOpenGLPixelFormat* pixelFormat = [
@@ -80,15 +82,7 @@ typedef NSUInteger NSWindowStyleMask;
PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
[super reshape];
- [wrapper dispatchConfigure:[self bounds]];
-}
-
-- (void) update
-{
- PuglWrapperView* wrapper = (PuglWrapperView*)[self superview];
-
- [super update];
- [wrapper dispatchConfigure:[self bounds]];
+ [wrapper setReshaped];
}
@end
@@ -104,10 +98,12 @@ 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:NSMakeRect(0, 0, view->width, view->height)];
- if (view->hints.resizable) {
+ [drawView initWithFrame:rect];
+ if (view->hints[PUGL_RESIZABLE]) {
[drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
} else {
[drawView setAutoresizingMask:NSViewNotSizable];
diff --git a/pugl/pugl/detail/types.h b/pugl/pugl/detail/types.h
index 60f7682..4ac224b 100644
--- a/pugl/pugl/detail/types.h
+++ b/pugl/pugl/detail/types.h
@@ -24,6 +24,7 @@
#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
@@ -35,46 +36,51 @@
# define PUGL_UNUSED(name)
#endif
-/** Platform-specific internals. */
+/** Platform-specific world internals. */
+typedef struct PuglWorldInternalsImpl PuglWorldInternals;
+
+/** Platform-specific view internals. */
typedef struct PuglInternalsImpl PuglInternals;
/** View hints. */
+typedef int PuglHints[PUGL_NUM_WINDOW_HINTS];
+
+/** Blob of arbitrary data. */
typedef struct {
- int context_version_major;
- int context_version_minor;
- int red_bits;
- int green_bits;
- int blue_bits;
- int alpha_bits;
- int depth_bits;
- int stencil_bits;
- int samples;
- int double_buffer;
- bool use_compat_profile;
- bool resizable;
- bool ignoreKeyRepeat;
-} PuglHints;
+ 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* windowClass;
+ char* title;
+ PuglBlob clipboard;
PuglNativeWindow parent;
- double start_time;
- uintptr_t transient_parent;
+ uintptr_t transientParent;
PuglHints hints;
- 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;
+ PuglRect frame;
+ int minWidth;
+ int minHeight;
+ int minAspectX;
+ int minAspectY;
+ int maxAspectX;
+ int maxAspectY;
bool visible;
+ bool redisplay;
+};
+
+/** Cross-platform world definition. */
+struct PuglWorldImpl {
+ PuglWorldInternals* impl;
+ char* className;
+ double startTime;
+ size_t numViews;
+ PuglView** views;
};
/** Opaque surface used by graphics backend. */
diff --git a/pugl/pugl/detail/win.c b/pugl/pugl/detail/win.c
index 93dce9d..25780e0 100644
--- a/pugl/pugl/detail/win.c
+++ b/pugl/pugl/detail/win.c
@@ -45,33 +45,70 @@
#endif
#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50)
+#define PUGL_LOCAL_MARK_MSG (WM_USER + 51)
#define PUGL_RESIZE_TIMER_ID 9461
#define PUGL_URGENT_TIMER_ID 9462
typedef BOOL (WINAPI *PFN_SetProcessDPIAware)(void);
-static const TCHAR* DEFAULT_CLASSNAME = "Pugl";
+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;
- }
+ 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;
+ return NULL;
}
-LRESULT CALLBACK
-wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+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;
+ }
-PuglInternals*
-puglInitInternals(void)
+ return NULL;
+}
+
+static bool
+puglRegisterWindowClass(const char* name)
{
- PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
+ 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(void)
+{
+ PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
+ 1, sizeof(PuglWorldInternals));
+ if (!impl) {
+ return NULL;
+ }
HMODULE user32 = LoadLibrary("user32.dll");
if (user32) {
@@ -81,6 +118,8 @@ puglInitInternals(void)
if (SetProcessDPIAware) {
SetProcessDPIAware();
}
+
+ FreeLibrary(user32);
}
LARGE_INTEGER frequency;
@@ -90,58 +129,64 @@ puglInitInternals(void)
return impl;
}
-int
+PuglInternals*
+puglInitViewInternals(void)
+{
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
+}
+
+PuglStatus
+puglPollEvents(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
puglCreateWindow(PuglView* view, const char* title)
{
PuglInternals* impl = view->impl;
- const char* className = view->windowClass ? view->windowClass : DEFAULT_CLASSNAME;
-
- title = title ? title : "Window";
+ title = title ? title : view->world->className;
// Get refresh rate for resize draw timer
DEVMODEA devMode = {0};
EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);
view->impl->refreshRate = devMode.dmDisplayFrequency;
- // Register window class
- 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 = className;
- if (!RegisterClassEx(&wc)) {
- return 1;
+ // Register window class if necessary
+ if (!puglRegisterWindowClass(view->world->className)) {
+ return PUGL_ERR_UNKNOWN;
}
if (!view->backend || !view->backend->configure) {
- return 1;
+ return PUGL_ERR_UNKNOWN;
}
int st = view->backend->configure(view);
if (st || !impl->surface) {
- return 2;
+ return PUGL_ERR_SET_FORMAT;
} else if ((st = view->backend->create(view))) {
- return 3;
+ return PUGL_ERR_CREATE_CONTEXT;
}
- wchar_t* wtitle = puglUtf8ToWideChar(title);
- if (wtitle) {
- SetWindowTextW(impl->hwnd, wtitle);
- free(wtitle);
+ if (title) {
+ puglSetWindowTitle(view, title);
}
SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view);
- return 0;
+ return PUGL_SUCCESS;
}
-void
+PuglStatus
puglShowWindow(PuglView* view)
{
PuglInternals* impl = view->impl;
@@ -149,31 +194,37 @@ puglShowWindow(PuglView* view)
ShowWindow(impl->hwnd, SW_SHOWNORMAL);
SetFocus(impl->hwnd);
view->visible = true;
+ return PUGL_SUCCESS;
}
-void
+PuglStatus
puglHideWindow(PuglView* view)
{
PuglInternals* impl = view->impl;
ShowWindow(impl->hwnd, SW_HIDE);
view->visible = false;
+ return PUGL_SUCCESS;
}
void
-puglDestroy(PuglView* view)
+puglFreeViewInternals(PuglView* view)
{
if (view) {
view->backend->destroy(view);
ReleaseDC(view->impl->hwnd, view->impl->hdc);
DestroyWindow(view->impl->hwnd);
- UnregisterClass(view->windowClass ? view->windowClass : DEFAULT_CLASSNAME, NULL);
- free(view->windowClass);
free(view->impl);
- free(view);
}
}
+void
+puglFreeWorldInternals(PuglWorld* world)
+{
+ UnregisterClass(world->className, NULL);
+ free(world->impl);
+}
+
static PuglKey
keySymToSpecial(WPARAM sym)
{
@@ -251,8 +302,8 @@ initMouseEvent(PuglEvent* event,
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.xRoot = pt.x;
+ event->button.yRoot = pt.y;
event->button.state = getModifiers();
event->button.button = (uint32_t)button;
}
@@ -267,8 +318,8 @@ initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam)
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.xRoot = GET_X_LPARAM(lParam);
+ event->scroll.yRoot = GET_Y_LPARAM(lParam);
event->scroll.state = getModifiers();
event->scroll.dx = 0;
event->scroll.dy = 0;
@@ -280,7 +331,7 @@ 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 (c0 >= 0xD800 && c0 < 0xDC00) {
if (len < 2) {
return 0xFFFD; // Surrogate, but length is only 1
} else if (c1 >= 0xDC00 && c1 <= 0xDFFF) {
@@ -290,7 +341,7 @@ puglDecodeUTF16(const wchar_t* buf, const int len)
return 0xFFFD; // Unpaired surrogates
}
- return c0;
+ return c0;
}
static void
@@ -319,8 +370,8 @@ initKeyEvent(PuglEventKey* event,
event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
event->time = GetMessageTime() / 1e3;
event->state = getModifiers();
- event->x_root = rpos.x;
- event->y_root = rpos.y;
+ event->xRoot = rpos.x;
+ event->yRoot = rpos.y;
event->x = cpos.x;
event->y = cpos.y;
event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16);
@@ -360,7 +411,7 @@ initCharEvent(PuglEvent* event, PuglView* view, WPARAM wParam, LPARAM lParam)
static bool
ignoreKeyEvent(PuglView* view, LPARAM lParam)
{
- return view->hints.ignoreKeyRepeat && (lParam & (1 << 30));
+ return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30));
}
static RECT
@@ -368,16 +419,25 @@ handleConfigure(PuglView* view, PuglEvent* event)
{
RECT rect;
GetClientRect(view->impl->hwnd, &rect);
- view->width = rect.right - rect.left;
- view->height = rect.bottom - rect.top;
+ MapWindowPoints(view->impl->hwnd,
+ view->parent ? (HWND)view->parent : HWND_DESKTOP,
+ (LPPOINT)&rect,
+ 2);
- event->configure.type = PUGL_CONFIGURE;
- event->configure.x = rect.left;
- event->configure.y = rect.top;
- event->configure.width = view->width;
- event->configure.height = view->height;
+ view->frame.x = rect.left;
+ view->frame.y = rect.top;
+ view->frame.width = rect.right - rect.left;
+ view->frame.height = rect.bottom - rect.top;
- view->backend->resize(view, view->width, view->height);
+ event->configure.type = PUGL_CONFIGURE;
+ event->configure.x = view->frame.x;
+ event->configure.y = view->frame.y;
+ event->configure.width = view->frame.width;
+ event->configure.height = view->frame.height;
+
+ view->backend->resize(view,
+ rect.right - rect.left,
+ rect.bottom - rect.top);
return rect;
}
@@ -415,8 +475,8 @@ constrainAspect(const PuglView* const view,
RECT* const size,
const WPARAM wParam)
{
- const float minA = (float)view->min_aspect_x / (float)view->min_aspect_y;
- const float maxA = (float)view->max_aspect_x / (float)view->max_aspect_y;
+ 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;
@@ -468,21 +528,21 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
switch (message) {
case WM_SHOWWINDOW:
rect = handleConfigure(view, &event);
- puglPostRedisplay(view);
+ RedrawWindow(view->impl->hwnd, NULL, NULL,
+ RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
break;
case WM_SIZE:
rect = handleConfigure(view, &event);
- RedrawWindow(view->impl->hwnd, NULL, NULL,
- RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT|
- RDW_UPDATENOW);
+ InvalidateRect(view->impl->hwnd, NULL, false);
break;
case WM_SIZING:
- if (view->min_aspect_x) {
+ 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,
@@ -498,14 +558,15 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
}
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->min_width;
- mmi->ptMinTrackSize.y = view->min_height;
+ mmi->ptMinTrackSize.x = view->minWidth;
+ mmi->ptMinTrackSize.y = view->minHeight;
break;
case WM_PAINT:
GetUpdateRect(view->impl->hwnd, &rect, false);
@@ -539,10 +600,10 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
event.motion.time = GetMessageTime() / 1e3;
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.xRoot = pt.x;
+ event.motion.yRoot = pt.y;
event.motion.state = getModifiers();
- event.motion.is_hint = false;
+ event.motion.isHint = false;
break;
case WM_MOUSELEAVE:
GetCursorPos(&pt);
@@ -615,20 +676,29 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
return 0;
}
-void
+PuglStatus
puglGrabFocus(PuglView* view)
{
SetFocus(view->impl->hwnd);
+ return PUGL_SUCCESS;
}
-void
+bool
+puglHasFocus(const PuglView* view)
+{
+ return GetFocus() == view->impl->hwnd;
+}
+
+PuglStatus
puglRequestAttention(PuglView* view)
{
- if (!view->impl->mouseTracked || GetFocus() != view->impl->hwnd) {
+ if (!view->impl->mouseTracked || !puglHasFocus(view)) {
FlashWindow(view->impl->hwnd, TRUE);
SetTimer(view->impl->hwnd, PUGL_URGENT_TIMER_ID, 500, NULL);
view->impl->flashing = true;
}
+
+ return PUGL_SUCCESS;
}
PuglStatus
@@ -638,18 +708,47 @@ puglWaitForEvent(PuglView* PUGL_UNUSED(view))
return PUGL_SUCCESS;
}
-PuglStatus
-puglProcessEvents(PuglView* view)
+PUGL_API PuglStatus
+puglDispatchEvents(PuglWorld* world)
{
- MSG msg;
- while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ for (size_t i = 0; i < world->numViews; ++i) {
+ if (world->views[i]->redisplay) {
+ UpdateWindow(world->views[i]->impl->hwnd);
+ world->views[i]->redisplay = false;
+ }
+ }
+
+ /* 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. */
+ PostMessage(NULL, PUGL_LOCAL_MARK_MSG, 0, 0);
+
+ long markTime = 0;
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 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;
}
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ return puglDispatchEvents(view->world);
+}
+
LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
@@ -674,20 +773,20 @@ wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
}
double
-puglGetTime(PuglView* view)
+puglGetTime(const PuglWorld* world)
{
- LARGE_INTEGER count;
- QueryPerformanceCounter(&count);
- const double now = (double)count.QuadPart / view->impl->timerFrequency;
- return now - view->start_time;
+ LARGE_INTEGER count;
+ QueryPerformanceCounter(&count);
+ return ((double)count.QuadPart / world->impl->timerFrequency -
+ world->startTime);
}
-void
+PuglStatus
puglPostRedisplay(PuglView* view)
{
- RedrawWindow(view->impl->hwnd, NULL, NULL,
- RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
- UpdateWindow(view->impl->hwnd);
+ InvalidateRect(view->impl->hwnd, NULL, false);
+ view->redisplay = true;
+ return PUGL_SUCCESS;
}
PuglNativeWindow
@@ -695,3 +794,133 @@ puglGetNativeWindow(PuglView* view)
{
return (PuglNativeWindow)view->impl->hwnd;
}
+
+PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title)
+{
+ puglSetString(&view->title, title);
+
+ 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_ERR_UNKNOWN;
+ }
+ }
+
+ 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_ERR_UNKNOWN;
+ }
+
+ // 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_ERR_UNKNOWN;
+ }
+
+ // Lock global memory
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (!wstr) {
+ GlobalFree(mem);
+ CloseClipboard();
+ return PUGL_ERR_UNKNOWN;
+ }
+
+ // 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;
+}
diff --git a/pugl/pugl/detail/win.h b/pugl/pugl/detail/win.h
index 9af5cbb..b9e554c 100644
--- a/pugl/pugl/detail/win.h
+++ b/pugl/pugl/detail/win.h
@@ -26,6 +26,10 @@
typedef PIXELFORMATDESCRIPTOR PuglWinPFD;
+struct PuglWorldInternalsImpl {
+ double timerFrequency;
+};
+
struct PuglInternalsImpl {
PuglWinPFD pfd;
int pfId;
@@ -33,55 +37,66 @@ struct PuglInternalsImpl {
HDC hdc;
PuglSurface* surface;
DWORD refreshRate;
- double timerFrequency;
bool flashing;
bool resizing;
bool mouseTracked;
};
static inline PuglWinPFD
-puglWinGetPixelFormatDescriptor(const PuglHints* const hints)
+puglWinGetPixelFormatDescriptor(const PuglHints hints)
{
- const int rgbBits = hints->red_bits + hints->green_bits + hints->blue_bits;
+ const int rgbBits = (hints[PUGL_RED_BITS] +
+ hints[PUGL_GREEN_BITS] +
+ hints[PUGL_BLUE_BITS]);
PuglWinPFD pfd;
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL;
- pfd.dwFlags |= hints->double_buffer ? PFD_DOUBLEBUFFER : 0;
+ pfd.dwFlags |= hints[PUGL_DOUBLE_BUFFER] ? PFD_DOUBLEBUFFER : 0;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = (BYTE)rgbBits;
- pfd.cRedBits = (BYTE)hints->red_bits;
- pfd.cGreenBits = (BYTE)hints->green_bits;
- pfd.cBlueBits = (BYTE)hints->blue_bits;
- pfd.cAlphaBits = (BYTE)hints->alpha_bits;
- pfd.cDepthBits = (BYTE)hints->depth_bits;
- pfd.cStencilBits = (BYTE)hints->stencil_bits;
+ 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];
+ return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
+ (view->parent
+ ? WS_CHILD
+ : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX |
+ (resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0))));
+}
+
+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 = view->windowClass ? view->windowClass : "Pugl";
-
- const unsigned winFlags =
- (WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
- (view->parent
- ? WS_CHILD
- : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX |
- (view->hints.resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0))));
-
- const unsigned winExFlags =
- WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW);
+ 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 = { 0, 0, view->width, view->height };
+ 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
diff --git a/pugl/pugl/detail/win_cairo.c b/pugl/pugl/detail/win_cairo.c
index 49175c1..cbca7e8 100644
--- a/pugl/pugl/detail/win_cairo.c
+++ b/pugl/pugl/detail/win_cairo.c
@@ -42,7 +42,7 @@ puglWinCairoCreateDrawContext(PuglView* view)
surface->drawDc = CreateCompatibleDC(impl->hdc);
surface->drawBitmap = CreateCompatibleBitmap(
- impl->hdc, view->width, view->height);
+ impl->hdc, (int)view->frame.width, (int)view->frame.height);
DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap));
@@ -87,7 +87,7 @@ puglWinCairoConfigure(PuglView* view)
return st;
}
- impl->pfd = puglWinGetPixelFormatDescriptor(&view->hints);
+ impl->pfd = puglWinGetPixelFormatDescriptor(view->hints);
impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd);
if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) {
@@ -150,7 +150,8 @@ puglWinCairoLeave(PuglView* view, bool drawing)
cairo_restore(surface->cr);
cairo_surface_flush(surface->surface);
- BitBlt(impl->hdc, 0, 0, view->width, view->height,
+ BitBlt(impl->hdc,
+ 0, 0, (int)view->frame.width, (int)view->frame.height,
surface->drawDc, 0, 0, SRCCOPY);
PAINTSTRUCT ps;
@@ -162,11 +163,9 @@ puglWinCairoLeave(PuglView* view, bool drawing)
static int
puglWinCairoResize(PuglView* view,
- int width,
- int height)
+ int PUGL_UNUSED(width),
+ int PUGL_UNUSED(height))
{
- view->width = width;
- view->height = height;
int st = 0;
if ((st = puglWinCairoDestroyDrawContext(view)) ||
(st = puglWinCairoCreateDrawContext(view))) {
diff --git a/pugl/pugl/detail/win_gl.c b/pugl/pugl/detail/win_gl.c
index 17ee68d..b7b03a4 100644
--- a/pugl/pugl/detail/win_gl.c
+++ b/pugl/pugl/detail/win_gl.c
@@ -111,16 +111,16 @@ puglWinGlConfigure(PuglView* view)
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.double_buffer,
+ WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER],
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
- WGL_SAMPLE_BUFFERS_ARB, view->hints.samples ? 1 : 0,
- WGL_SAMPLES_ARB, view->hints.samples,
- WGL_RED_BITS_ARB, view->hints.red_bits,
- WGL_GREEN_BITS_ARB, view->hints.green_bits,
- WGL_BLUE_BITS_ARB, view->hints.blue_bits,
- WGL_ALPHA_BITS_ARB, view->hints.alpha_bits,
- WGL_DEPTH_BITS_ARB, view->hints.depth_bits,
- WGL_STENCIL_BITS_ARB, view->hints.stencil_bits,
+ 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,
};
@@ -137,7 +137,7 @@ puglWinGlConfigure(PuglView* view)
}
// Set pixel format for fake window
- const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(&view->hints);
+ const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints);
const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd);
if (!fakePfId) {
return puglWinError(&fakeWin, PUGL_ERR_SET_FORMAT);
@@ -188,10 +188,10 @@ puglWinGlCreate(PuglView* view)
PuglStatus st = PUGL_SUCCESS;
const int contextAttribs[] = {
- WGL_CONTEXT_MAJOR_VERSION_ARB, view->hints.context_version_major,
- WGL_CONTEXT_MINOR_VERSION_ARB, view->hints.context_version_minor,
+ WGL_CONTEXT_MAJOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MAJOR],
+ WGL_CONTEXT_MINOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MINOR],
WGL_CONTEXT_PROFILE_MASK_ARB,
- (view->hints.use_compat_profile
+ (view->hints[PUGL_USE_COMPAT_PROFILE]
? WGL_CONTEXT_CORE_PROFILE_BIT_ARB
: WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB),
0
@@ -220,7 +220,7 @@ puglWinGlCreate(PuglView* view)
// Enter context and set swap interval
wglMakeCurrent(impl->hdc, surface->hglrc);
if (surface->procs.wglSwapInterval) {
- surface->procs.wglSwapInterval(1);
+ surface->procs.wglSwapInterval(view->hints[PUGL_SWAP_INTERVAL]);
}
return 0;
@@ -286,7 +286,15 @@ puglWinGlGetContext(PuglView* PUGL_UNUSED(view))
PuglGlFunc
puglGetProcAddress(const char* name)
{
- return (PuglGlFunc)wglGetProcAddress(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*
diff --git a/pugl/pugl/detail/x11.c b/pugl/pugl/detail/x11.c
index d6461a2..adf8c9d 100644
--- a/pugl/pugl/detail/x11.c
+++ b/pugl/pugl/detail/x11.c
@@ -28,12 +28,15 @@
#include "pugl/pugl.h"
#include <X11/X.h>
+#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
+#include <sys/select.h>
#include <sys/time.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -60,22 +63,21 @@ static const long eventMask =
EnterWindowMask | LeaveWindowMask | PointerMotionMask |
ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask);
-PuglInternals*
-puglInitInternals(void)
+PuglWorldInternals*
+puglInitWorldInternals(void)
{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
-}
+ Display* display = XOpenDisplay(NULL);
+ if (!display) {
+ return NULL;
+ }
-int
-puglCreateWindow(PuglView* view, const char* title)
-{
- PuglInternals* const impl = view->impl;
- Display* const display = XOpenDisplay(0);
+ PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
+ 1, sizeof(PuglWorldInternals));
impl->display = display;
- impl->screen = DefaultScreen(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);
@@ -84,6 +86,104 @@ puglCreateWindow(PuglView* view, const char* title)
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=");
+ if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) {
+ fprintf(stderr, "warning: XOpenIM failed\n");
+ }
+ }
+
+ XFlush(display);
+
+ return impl;
+}
+
+PuglInternals*
+puglInitViewInternals(void)
+{
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
+}
+
+PuglStatus
+puglPollEvents(PuglWorld* world, const double timeout)
+{
+ XFlush(world->impl->display);
+
+ const int fd = ConnectionNumber(world->impl->display);
+ const int nfds = fd + 1;
+ int ret = 0;
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ if (timeout < 0.0) {
+ ret = select(nfds, &fds, NULL, NULL, NULL);
+ } else {
+ const long sec = (long)timeout;
+ const long msec = (long)((timeout - (double)sec) * 1e6);
+ struct timeval tv = {sec, msec};
+ ret = select(nfds, &fds, NULL, NULL, &tv);
+ }
+
+ return ret < 0 ? PUGL_ERR_UNKNOWN : ret == 0 ? PUGL_FAILURE : 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
+puglCreateWindow(PuglView* view, const char* title)
+{
+ PuglInternals* const impl = view->impl;
+ PuglWorld* const world = view->world;
+ PuglX11Atoms* const atoms = &view->world->impl->atoms;
+ Display* const display = world->impl->display;
+ const int width = (int)view->frame.width;
+ const int height = (int)view->frame.height;
+
+ impl->display = display;
+ impl->screen = DefaultScreen(display);
+
if (!view->backend || !view->backend->configure) {
return 1;
} else if (view->backend->configure(view) || !impl->vi) {
@@ -103,61 +203,35 @@ puglCreateWindow(PuglView* view, const char* title)
const Window win = impl->win = XCreateWindow(
display, xParent,
- 0, 0, view->width, view->height, 0, impl->vi->depth, InputOutput,
+ (int)view->frame.x, (int)view->frame.y, width, height,
+ 0, impl->vi->depth, InputOutput,
impl->vi->visual, CWColormap | CWEventMask, &attr);
if (view->backend->create(view)) {
return 3;
}
- XSizeHints sizeHints = {0};
- if (!view->hints.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;
- } else {
- if (view->min_width || view->min_height) {
- sizeHints.flags = PMinSize;
- sizeHints.min_width = view->min_width;
- sizeHints.min_height = view->min_height;
- }
- if (view->min_aspect_x) {
- sizeHints.flags |= PAspect;
- sizeHints.min_aspect.x = view->min_aspect_x;
- sizeHints.min_aspect.y = view->min_aspect_y;
- sizeHints.max_aspect.x = view->max_aspect_x;
- sizeHints.max_aspect.y = view->max_aspect_y;
- }
- }
+ XSizeHints sizeHints = getSizeHints(view);
XSetNormalHints(display, win, &sizeHints);
+ XClassHint classHint = { world->className, world->className };
+ XSetClassHint(display, win, &classHint);
+
if (title) {
- XStoreName(display, win, title);
- XChangeProperty(display, win,
- impl->atoms.NET_WM_NAME, impl->atoms.UTF8_STRING, 8,
- PropModeReplace, (const uint8_t*)title, strlen(title));
+ puglSetWindowTitle(view, title);
}
if (!view->parent) {
- XSetWMProtocols(display, win, &view->impl->atoms.WM_DELETE_WINDOW, 1);
+ XSetWMProtocols(display, win, &atoms->WM_DELETE_WINDOW, 1);
}
- if (view->transient_parent) {
- XSetTransientForHint(display, win, (Window)(view->transient_parent));
- }
-
- XSetLocaleModifiers("");
- if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) {
- XSetLocaleModifiers("@im=");
- if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) {
- fprintf(stderr, "warning: XOpenIM failed\n");
- }
+ if (view->transientParent) {
+ XSetTransientForHint(display, win, (Window)(view->transientParent));
}
+ // Create input context
const XIMStyle im_style = XIMPreeditNothing | XIMStatusNothing;
- if (!(impl->xic = XCreateIC(impl->xim,
+ if (!(impl->xic = XCreateIC(world->impl->xim,
XNInputStyle, im_style,
XNClientWindow, win,
XNFocusWindow, win,
@@ -168,40 +242,47 @@ puglCreateWindow(PuglView* view, const char* title)
return 0;
}
-void
+PuglStatus
puglShowWindow(PuglView* view)
{
XMapRaised(view->impl->display, view->impl->win);
+ puglPostRedisplay(view);
view->visible = true;
+ return PUGL_SUCCESS;
}
-void
+PuglStatus
puglHideWindow(PuglView* view)
{
XUnmapWindow(view->impl->display, view->impl->win);
view->visible = false;
+ return PUGL_SUCCESS;
}
void
-puglDestroy(PuglView* view)
+puglFreeViewInternals(PuglView* view)
{
if (view) {
if (view->impl->xic) {
XDestroyIC(view->impl->xic);
}
- if (view->impl->xim) {
- XCloseIM(view->impl->xim);
- }
view->backend->destroy(view);
XDestroyWindow(view->impl->display, view->impl->win);
- XCloseDisplay(view->impl->display);
XFree(view->impl->vi);
- free(view->windowClass);
free(view->impl);
- free(view);
}
}
+void
+puglFreeWorldInternals(PuglWorld* world)
+{
+ if (world->impl->xim) {
+ XCloseIM(world->impl->xim);
+ }
+ XCloseDisplay(world->impl->display);
+ free(world->impl);
+}
+
static PuglKey
keySymToSpecial(KeySym sym)
{
@@ -310,14 +391,16 @@ translateModifiers(const unsigned xstate)
static PuglEvent
translateEvent(PuglView* view, XEvent xevent)
{
+ const PuglX11Atoms* atoms = &view->world->impl->atoms;
+
PuglEvent event = {0};
event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0;
switch (xevent.type) {
case ClientMessage:
- if (xevent.xclient.message_type == view->impl->atoms.WM_PROTOCOLS) {
+ if (xevent.xclient.message_type == atoms->WM_PROTOCOLS) {
const Atom protocol = (Atom)xevent.xclient.data.l[0];
- if (protocol == view->impl->atoms.WM_DELETE_WINDOW) {
+ if (protocol == atoms->WM_DELETE_WINDOW) {
event.type = PUGL_CLOSE;
}
}
@@ -352,10 +435,10 @@ translateEvent(PuglView* view, XEvent xevent)
event.motion.time = xevent.xmotion.time / 1e3;
event.motion.x = xevent.xmotion.x;
event.motion.y = xevent.xmotion.y;
- event.motion.x_root = xevent.xmotion.x_root;
- event.motion.y_root = xevent.xmotion.y_root;
+ event.motion.xRoot = xevent.xmotion.x_root;
+ event.motion.yRoot = xevent.xmotion.y_root;
event.motion.state = translateModifiers(xevent.xmotion.state);
- event.motion.is_hint = (xevent.xmotion.is_hint == NotifyHint);
+ event.motion.isHint = (xevent.xmotion.is_hint == NotifyHint);
break;
case ButtonPress:
if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) {
@@ -363,8 +446,8 @@ translateEvent(PuglView* view, XEvent xevent)
event.scroll.time = xevent.xbutton.time / 1e3;
event.scroll.x = xevent.xbutton.x;
event.scroll.y = xevent.xbutton.y;
- event.scroll.x_root = xevent.xbutton.x_root;
- event.scroll.y_root = xevent.xbutton.y_root;
+ 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;
@@ -385,8 +468,8 @@ translateEvent(PuglView* view, XEvent xevent)
event.button.time = xevent.xbutton.time / 1e3;
event.button.x = xevent.xbutton.x;
event.button.y = xevent.xbutton.y;
- event.button.x_root = xevent.xbutton.x_root;
- event.button.y_root = xevent.xbutton.y_root;
+ 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;
}
@@ -399,8 +482,8 @@ translateEvent(PuglView* view, XEvent xevent)
event.key.time = xevent.xkey.time / 1e3;
event.key.x = xevent.xkey.x;
event.key.y = xevent.xkey.y;
- event.key.x_root = xevent.xkey.x_root;
- event.key.y_root = xevent.xkey.y_root;
+ 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;
@@ -412,8 +495,8 @@ translateEvent(PuglView* view, XEvent xevent)
event.crossing.time = xevent.xcrossing.time / 1e3;
event.crossing.x = xevent.xcrossing.x;
event.crossing.y = xevent.xcrossing.y;
- event.crossing.x_root = xevent.xcrossing.x_root;
- event.crossing.y_root = xevent.xcrossing.y_root;
+ 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) {
@@ -436,24 +519,36 @@ translateEvent(PuglView* view, XEvent xevent)
return event;
}
-void
+PuglStatus
puglGrabFocus(PuglView* view)
{
XSetInputFocus(
- view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime);
+ view->impl->display, view->impl->win, RevertToNone, CurrentTime);
+ return PUGL_SUCCESS;
}
-void
+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;
- XEvent event = {0};
+ 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 = impl->atoms.NET_WM_STATE;
+ event.xclient.message_type = atoms->NET_WM_STATE;
event.xclient.data.l[0] = WM_STATE_ADD;
- event.xclient.data.l[1] = impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION;
+ event.xclient.data.l[1] = atoms->NET_WM_STATE_DEMANDS_ATTENTION;
event.xclient.data.l[2] = 0;
event.xclient.data.l[3] = 1;
event.xclient.data.l[4] = 0;
@@ -464,6 +559,8 @@ puglRequestAttention(PuglView* view)
False,
SubstructureNotifyMask | SubstructureRedirectMask,
&event);
+
+ return PUGL_SUCCESS;
}
PuglStatus
@@ -493,35 +590,106 @@ merge_expose_events(PuglEvent* dst, const PuglEvent* src)
}
}
-PuglStatus
-puglProcessEvents(PuglView* view)
+static void
+sendRedisplayEvent(PuglView* view)
+{
+ XExposeEvent ev = { Expose, 0, True, view->impl->display, view->impl->win,
+ 0, 0, (int)view->frame.width, (int)view->frame.height,
+ 0 };
+
+ XSendEvent(view->impl->display, view->impl->win, False, 0, (XEvent*)&ev);
+}
+
+PUGL_API PuglStatus
+puglDispatchEvents(PuglWorld* world)
{
- /* Maintain a single expose/configure event to execute after all pending
- events. This avoids redundant drawing/configuration which prevents a
- series of window resizes in the same loop from being laggy. */
- PuglInternals* const impl = view->impl;
- PuglEvent expose_event = { 0 };
- PuglEvent config_event = { 0 };
- XEvent xevent;
- while (XPending(impl->display) > 0) {
- XNextEvent(impl->display, &xevent);
- if (xevent.type == KeyRelease) {
- // Ignore key repeat if necessary
- if (view->hints.ignoreKeyRepeat &&
- XEventsQueued(impl->display, QueuedAfterReading)) {
- XEvent next;
- XPeekEvent(impl->display, &next);
- if (next.type == KeyPress &&
- next.xkey.time == xevent.xkey.time &&
- next.xkey.keycode == xevent.xkey.keycode) {
- XNextEvent(impl->display, &xevent);
- continue;
- }
+ const PuglX11Atoms* const atoms = &world->impl->atoms;
+
+ // Send expose events for any views with pending redisplays
+ for (size_t i = 0; i < world->numViews; ++i) {
+ if (world->views[i]->redisplay) {
+ sendRedisplayEvent(world->views[i]);
+ world->views[i]->redisplay = false;
+ }
+ }
+
+ // Flush just once at the start to fill event queue
+ Display* display = world->impl->display;
+ XFlush(display);
+
+ // Process all queued events (locally, without flushing or reading)
+ while (XEventsQueued(display, QueuedAlready) > 0) {
+ XEvent xevent;
+ XNextEvent(display, &xevent);
+
+ 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);
+ continue;
+ } else if (xevent.type == SelectionNotify &&
+ xevent.xselection.selection == atoms->CLIPBOARD &&
+ xevent.xselection.target == atoms->UTF8_STRING &&
+ xevent.xselection.property == XA_PRIMARY) {
+
+ uint8_t* str = NULL;
+ Atom type = 0;
+ int fmt = 0;
+ unsigned long len = 0;
+ unsigned long left = 0;
+ XGetWindowProperty(impl->display, impl->win, XA_PRIMARY,
+ 0, 8, False, AnyPropertyType,
+ &type, &fmt, &len, &left, &str);
+
+ if (str && fmt == 8 && type == atoms->UTF8_STRING && left == 0) {
+ puglSetBlob(&view->clipboard, str, len);
+ }
+
+ XFree(str);
+ continue;
+ } else if (xevent.type == SelectionRequest) {
+ const XSelectionRequestEvent* request = &xevent.xselectionrequest;
+
+ XSelectionEvent note = {0};
+ note.type = SelectionNotify;
+ note.requestor = request->requestor;
+ note.selection = request->selection;
+ note.target = request->target;
+ note.time = request->time;
+
+ const char* type = NULL;
+ size_t len = 0;
+ const void* data = puglGetInternalClipboard(view, &type, &len);
+ if (data &&
+ request->selection == atoms->CLIPBOARD &&
+ request->target == atoms->UTF8_STRING) {
+ note.property = request->property;
+ XChangeProperty(impl->display, note.requestor,
+ note.property, note.target, 8, PropModeReplace,
+ (const uint8_t*)data, len);
+ } else {
+ note.property = None;
+ }
+
+ XSendEvent(impl->display, note.requestor, True, 0, (XEvent*)&note);
+ continue;
}
// Translate X11 event to Pugl event
@@ -529,56 +697,70 @@ puglProcessEvents(PuglView* view)
if (event.type == PUGL_EXPOSE) {
// Expand expose event to be dispatched after loop
- merge_expose_events(&expose_event, &event);
+ merge_expose_events(&view->impl->pendingExpose, &event);
} else if (event.type == PUGL_CONFIGURE) {
// Expand configure event to be dispatched after loop
- config_event = event;
+ view->impl->pendingConfigure = event;
} else {
// Dispatch event to application immediately
puglDispatchEvent(view, &event);
}
}
- if (config_event.type || expose_event.type) {
- const bool draw = expose_event.type && expose_event.expose.count == 0;
-
- puglEnterContext(view, draw);
+ // Flush pending configure and expose events for all views
+ for (size_t i = 0; i < world->numViews; ++i) {
+ PuglView* const view = world->views[i];
+ PuglEvent* const configure = &view->impl->pendingConfigure;
+ PuglEvent* const expose = &view->impl->pendingExpose;
+
+ if (configure->type || expose->type) {
+ const bool mustExpose = expose->type && expose->expose.count == 0;
+ puglEnterContext(view, mustExpose);
+
+ if (configure->type) {
+ view->frame.x = configure->configure.x;
+ view->frame.y = configure->configure.y;
+ view->frame.width = configure->configure.width;
+ view->frame.height = configure->configure.height;
+
+ view->backend->resize(view,
+ (int)view->frame.width,
+ (int)view->frame.height);
+ view->eventFunc(view, &view->impl->pendingConfigure);
+ }
- if (config_event.type) {
- view->width = (int)config_event.configure.width;
- view->height = (int)config_event.configure.height;
- view->backend->resize(view, view->width, view->height);
- view->eventFunc(view, (const PuglEvent*)&config_event);
- }
+ if (mustExpose) {
+ view->eventFunc(view, &view->impl->pendingExpose);
+ }
- if (draw) {
- view->eventFunc(view, (const PuglEvent*)&expose_event);
+ puglLeaveContext(view, mustExpose);
+ configure->type = 0;
+ expose->type = 0;
}
-
- puglLeaveContext(view, draw);
}
return PUGL_SUCCESS;
}
+PuglStatus
+puglProcessEvents(PuglView* view)
+{
+ return puglDispatchEvents(view->world);
+}
+
double
-puglGetTime(PuglView* view)
+puglGetTime(const PuglWorld* world)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
- return ((double)ts.tv_sec + ts.tv_nsec / 1000000000.0) - view->start_time;
+ return ((double)ts.tv_sec + ts.tv_nsec / 1000000000.0) - world->startTime;
}
-void
+PuglStatus
puglPostRedisplay(PuglView* view)
{
- XExposeEvent ev = {Expose, 0, True,
- view->impl->display, view->impl->win,
- 0, 0,
- view->width, view->height,
- 0};
-
- XSendEvent(view->impl->display, view->impl->win, False, 0, (XEvent*)&ev);
+ view->redisplay = true;
+ return PUGL_SUCCESS;
}
PuglNativeWindow
@@ -586,3 +768,135 @@ puglGetNativeWindow(PuglView* view)
{
return (PuglNativeWindow)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);
+ 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,
+ (int)frame.width, (int)frame.height)) {
+ return PUGL_ERR_UNKNOWN;
+ }
+
+ 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, PuglNativeWindow 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) {
+ puglPollEvents(view->world, -1);
+ puglDispatchEvents(view->world);
+ }
+ }
+
+ 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;
+}
diff --git a/pugl/pugl/detail/x11.h b/pugl/pugl/detail/x11.h
index 1ead119..bfdbf60 100644
--- a/pugl/pugl/detail/x11.h
+++ b/pugl/pugl/detail/x11.h
@@ -23,21 +23,29 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
+typedef struct {
+ Atom CLIPBOARD;
+ Atom UTF8_STRING;
+ Atom WM_PROTOCOLS;
+ Atom WM_DELETE_WINDOW;
+ Atom NET_WM_NAME;
+ Atom NET_WM_STATE;
+ Atom NET_WM_STATE_DEMANDS_ATTENTION;
+} PuglX11Atoms;
+
+struct PuglWorldInternalsImpl {
+ Display* display;
+ PuglX11Atoms atoms;
+ XIM xim;
+};
+
struct PuglInternalsImpl {
Display* display;
int screen;
XVisualInfo* vi;
Window win;
- XIM xim;
XIC xic;
PuglSurface* surface;
-
- struct {
- Atom UTF8_STRING;
- Atom WM_PROTOCOLS;
- Atom WM_DELETE_WINDOW;
- Atom NET_WM_NAME;
- Atom NET_WM_STATE;
- Atom NET_WM_STATE_DEMANDS_ATTENTION;
- } atoms;
+ PuglEvent pendingConfigure;
+ PuglEvent pendingExpose;
};
diff --git a/pugl/pugl/detail/x11_cairo.c b/pugl/pugl/detail/x11_cairo.c
index d5e2ed7..550144a 100644
--- a/pugl/pugl/detail/x11_cairo.c
+++ b/pugl/pugl/detail/x11_cairo.c
@@ -55,8 +55,8 @@ static int
puglX11CairoCreate(PuglView* view)
{
PuglInternals* const impl = view->impl;
- const int width = view->width;
- const int height = view->height;
+ const int width = (int)view->frame.width;
+ const int height = (int)view->frame.height;
PuglX11CairoSurface surface = { 0 };
surface.back = cairo_xlib_surface_create(
diff --git a/pugl/pugl/detail/x11_gl.c b/pugl/pugl/detail/x11_gl.c
index 85c18b4..b6f3c51 100644
--- a/pugl/pugl/detail/x11_gl.c
+++ b/pugl/pugl/detail/x11_gl.c
@@ -71,14 +71,14 @@ puglX11GlConfigure(PuglView* view)
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_SAMPLES, view->hints.samples,
- GLX_RED_SIZE, puglX11GlHintValue(view->hints.red_bits),
- GLX_GREEN_SIZE, puglX11GlHintValue(view->hints.green_bits),
- GLX_BLUE_SIZE, puglX11GlHintValue(view->hints.blue_bits),
- GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints.alpha_bits),
- GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints.depth_bits),
- GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints.stencil_bits),
- GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints.double_buffer),
+ 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
};
@@ -117,9 +117,9 @@ puglX11GlCreate(PuglView* view)
const GLXFBConfig fb_config = surface->fb_config;
const int ctx_attrs[] = {
- GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints.context_version_major,
- GLX_CONTEXT_MINOR_VERSION_ARB, view->hints.context_version_minor,
- GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints.use_compat_profile
+ GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MAJOR],
+ GLX_CONTEXT_MINOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MINOR],
+ GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints[PUGL_USE_COMPAT_PROFILE]
? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB),
0};
diff --git a/pugl/pugl/pugl.h b/pugl/pugl/pugl.h
index d04f1aa..cdb73af 100644
--- a/pugl/pugl/pugl.h
+++ b/pugl/pugl/pugl.h
@@ -15,13 +15,14 @@
*/
/**
- @file pugl.h Public Pugl API.
+ @file pugl.h Public C API.
*/
#ifndef PUGL_H_INCLUDED
#define PUGL_H_INCLUDED
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#ifdef PUGL_SHARED
@@ -41,44 +42,17 @@
# define PUGL_API
#endif
-#if defined(__clang__)
-# define PUGL_DEPRECATED_BY(name) __attribute__((deprecated("", name)))
-#elif defined(__GNUC__)
-# define PUGL_DEPRECATED_BY(name) __attribute__((deprecated("Use " name)))
-#else
-# define PUGL_DEPRECATED_BY(name)
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
/**
@defgroup pugl Pugl
- A minimal portable API for OpenGL.
+ Pugl C API.
@{
*/
/**
- A Pugl view.
-*/
-typedef struct PuglViewImpl PuglView;
-
-/**
- Graphics backend interface.
-*/
-typedef struct PuglBackendImpl PuglBackend;
-
-/**
- A native window handle.
-
- On X11, this is a Window.
- On OSX, this is an NSView*.
- On Windows, this is a HWND.
-*/
-typedef intptr_t PuglNativeWindow;
-
-/**
Handle for opaque user data.
*/
typedef void* PuglHandle;
@@ -88,9 +62,12 @@ typedef void* PuglHandle;
*/
typedef enum {
PUGL_SUCCESS,
+ PUGL_FAILURE,
+ PUGL_ERR_UNKNOWN,
PUGL_ERR_CREATE_WINDOW,
PUGL_ERR_SET_FORMAT,
PUGL_ERR_CREATE_CONTEXT,
+ PUGL_ERR_UNSUPPORTED_TYPE,
} PuglStatus;
/**
@@ -108,9 +85,12 @@ typedef enum {
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 window should be resizable */
PUGL_IGNORE_KEY_REPEAT, /**< True if key repeat events are ignored */
-} PuglWindowHint;
+
+ PUGL_NUM_WINDOW_HINTS
+} PuglViewHint;
/**
Special window hint value.
@@ -119,7 +99,20 @@ typedef enum {
PUGL_DONT_CARE = -1, /**< Use best available value */
PUGL_FALSE = 0, /**< Explicitly false */
PUGL_TRUE = 1 /**< Explicitly true */
-} PuglWindowHintValue;
+} PuglViewHintValue;
+
+/**
+ A rectangle.
+
+ This is used to describe things like view position and size. Pugl generally
+ uses coordinates where the top left corner is 0,0.
+*/
+typedef struct {
+ double x;
+ double y;
+ double width;
+ double height;
+} PuglRect;
/**
Keyboard modifier flags.
@@ -244,8 +237,8 @@ typedef struct {
double time; /**< Time in seconds. */
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. */
+ double xRoot; /**< Root-relative X coordinate. */
+ double yRoot; /**< Root-relative Y coordinate. */
uint32_t state; /**< Bitwise OR of PuglMod flags. */
uint32_t button; /**< 1-relative button number. */
} PuglEventButton;
@@ -301,8 +294,8 @@ typedef struct {
double time; /**< Time in seconds. */
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. */
+ double xRoot; /**< Root-relative X coordinate. */
+ double yRoot; /**< Root-relative Y coordinate. */
uint32_t state; /**< Bitwise OR of PuglMod flags. */
uint32_t keycode; /**< Raw key code. */
uint32_t key; /**< Unshifted Unicode character code, or 0. */
@@ -320,8 +313,8 @@ typedef struct {
double time; /**< Time in seconds. */
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. */
+ double xRoot; /**< Root-relative X coordinate. */
+ double yRoot; /**< Root-relative Y coordinate. */
uint32_t state; /**< Bitwise OR of PuglMod flags. */
uint32_t keycode; /**< Raw key code. */
uint32_t character; /**< Unicode character code */
@@ -337,8 +330,8 @@ typedef struct {
double time; /**< Time in seconds. */
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. */
+ double xRoot; /**< Root-relative X coordinate. */
+ double yRoot; /**< Root-relative Y coordinate. */
uint32_t state; /**< Bitwise OR of PuglMod flags. */
PuglCrossingMode mode; /**< Reason for crossing. */
} PuglEventCrossing;
@@ -352,10 +345,10 @@ typedef struct {
double time; /**< Time in seconds. */
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. */
+ double xRoot; /**< Root-relative X coordinate. */
+ double yRoot; /**< Root-relative Y coordinate. */
uint32_t state; /**< Bitwise OR of PuglMod flags. */
- bool is_hint; /**< True iff this event is a motion hint. */
+ bool isHint; /**< True iff this event is a motion hint. */
bool focus; /**< True iff this is the focused window. */
} PuglEventMotion;
@@ -374,8 +367,8 @@ typedef struct {
double time; /**< Time in seconds. */
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. */
+ double xRoot; /**< Root-relative X coordinate. */
+ double yRoot; /**< Root-relative Y coordinate. */
uint32_t state; /**< Bitwise OR of PuglMod flags. */
double dx; /**< Scroll X distance in lines. */
double dy; /**< Scroll Y distance in lines. */
@@ -413,56 +406,184 @@ typedef union {
} PuglEvent;
/**
- @name Initialization
- Configuration functions which must be called before creating a window.
+ @anchor world
+ @name World
+ The top level context of a Pugl application.
@{
*/
/**
- Create a Pugl view.
+ The "world" of application state.
- To create a window, call the various puglInit* functions as necessary, then
- call puglCreateWindow().
+ The world represents things that are not associated with a particular view.
+ Several worlds can be created in a process (which is the case when many
+ plugins use Pugl, for example), but code using different worlds must be
+ isolated so they are never mixed. Views are strongly associated with the
+ world they were created for.
+*/
+typedef struct PuglWorldImpl PuglWorld;
- @param pargc Pointer to argument count (currently unused).
- @param argv Arguments (currently unused).
- @return A newly created view.
+/**
+ Create a new world.
+
+ @return A newly created world.
*/
-PUGL_API PuglView*
-puglInit(int* pargc, char** argv);
+PUGL_API PuglWorld*
+puglNewWorld(void);
/**
- Set a hint before creating a window.
+ Free a world allocated with puglNewWorld().
*/
PUGL_API void
-puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value);
+puglFreeWorld(PuglWorld* world);
/**
- Set the window class name before creating a window.
+ 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 void
-puglInitWindowClass(PuglView* view, const char* name);
+PUGL_API PuglStatus
+puglSetClassName(PuglWorld* world, const char* name);
/**
- Set the parent window before creating a window (for embedding).
+ 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 void
-puglInitWindowParent(PuglView* view, PuglNativeWindow parent);
+PUGL_API double
+puglGetTime(const PuglWorld* world);
/**
- Set the window size before creating a window.
+ Poll for events that are ready to be processed.
+
+ This polls for events that are ready for any view in the application,
+ potentially blocking depending on `timeout`.
+
+ @param world The world for all the views to poll.
+ @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
+puglPollEvents(PuglWorld* world, double timeout);
+
+/**
+ 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 it will return
+ immediately.
+*/
+PUGL_API PuglStatus
+puglDispatchEvents(PuglWorld* world);
+
+/**
+ @}
+ @anchor view
+ @name View
+ A view is a drawing region that receives events, which may correspond to a
+ top-level window or be embedded in some other window.
+ @{
+*/
+
+/**
+ A Pugl view.
+*/
+typedef struct PuglViewImpl PuglView;
+
+/**
+ Create a new view.
+
+ A view represents a window, but a window will not be shown until configured
+ with the various puglInit functions and shown with puglShowWindow().
+*/
+PUGL_API PuglView*
+puglNewView(PuglWorld* world);
+
+/**
+ Free a view created with puglNewView().
*/
PUGL_API void
-puglInitWindowSize(PuglView* view, int width, int height);
+puglFreeView(PuglView* view);
/**
- Set the minimum window size before creating a window.
+ Return the world that `view` is a part of.
+*/
+PUGL_API PuglWorld*
+puglGetWorld(PuglView* view);
+
+/**
+ Set the handle to be passed to all callbacks.
+
+ This is generally a pointer to a struct which contains all necessary state.
+ Everything needed in callbacks should be here, not in static variables.
*/
PUGL_API void
-puglInitWindowMinSize(PuglView* view, int width, int height);
+puglSetHandle(PuglView* view, PuglHandle handle);
/**
- Set the window aspect ratio range before creating a window.
+ Get the handle to be passed to all callbacks.
+*/
+PUGL_API PuglHandle
+puglGetHandle(PuglView* view);
+
+/**
+ Set a hint to configure window properties.
+
+ This only has an effect when called before puglCreateWindow().
+*/
+PUGL_API PuglStatus
+puglSetViewHint(PuglView* view, PuglViewHint hint, int value);
+
+/**
+ Return true iff the view is currently visible.
+*/
+PUGL_API bool
+puglGetVisible(PuglView* view);
+
+/**
+ Request a redisplay on the next call to puglDispatchEvents().
+*/
+PUGL_API PuglStatus
+puglPostRedisplay(PuglView* view);
+
+/**
+ @}
+ @anchor frame
+ @name Frame
+ Functions for working with the position and size of a view.
+ @{
+*/
+
+/**
+ Get the current position and size of the view.
+*/
+PUGL_API PuglRect
+puglGetFrame(const PuglView* view);
+
+/**
+ Set the current position and size of the view.
+*/
+PUGL_API PuglStatus
+puglSetFrame(PuglView* view, PuglRect frame);
+
+/**
+ Set the minimum size of the view.
+
+ To avoid stutter, this should be called before creating the window.
+*/
+PUGL_API PuglStatus
+puglSetMinSize(PuglView* view, int width, int height);
+
+/**
+ Set the window 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.
@@ -471,66 +592,71 @@ puglInitWindowMinSize(PuglView* view, int width, int height);
currenty work on MacOS (the minimum is used), so only setting a fixed aspect
ratio works properly across all platforms.
*/
-PUGL_API void
-puglInitWindowAspectRatio(PuglView* view,
- int min_x,
- int min_y,
- int max_x,
- int max_y);
+PUGL_API PuglStatus
+puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY);
/**
- Enable or disable resizing before creating a window.
+ @}
+ @name Windows
+ Functions for working with top-level windows.
+ @{
+*/
- @deprecated Use puglInitWindowHint() with @ref PUGL_RESIZABLE.
+/**
+ A native window handle.
+
+ On X11, this is a Window.
+ On OSX, this is an NSView*.
+ On Windows, this is a HWND.
*/
-PUGL_API PUGL_DEPRECATED_BY("puglInitWindowHint") void
-puglInitResizable(PuglView* view, bool resizable);
+typedef intptr_t PuglNativeWindow;
/**
- Set transient parent before creating a window.
+ Set the title of the window.
- On X11, parent must be a Window.
- On OSX, parent must be an NSView*.
+ 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 void
-puglInitTransientFor(PuglView* view, uintptr_t parent);
+PUGL_API PuglStatus
+puglSetWindowTitle(PuglView* view, const char* title);
/**
- Set the graphics backend to use.
+ Set the parent window before creating a window (for embedding).
- This needs to be called once before creating the window to set the graphics
- backend. There are two backend accessors included with pugl:
- puglGlBackend() and puglCairoBackend(), declared in pugl_gl_backend.h and
- pugl_cairo_backend.h, respectively.
+ This only works when called before creating the window with
+ puglCreateWindow(), reparenting is not supported.
*/
-PUGL_API int
-puglInitBackend(PuglView* view, const PuglBackend* backend);
+PUGL_API PuglStatus
+puglSetParentWindow(PuglView* view, PuglNativeWindow parent);
/**
- @}
- @name Windows
- Functions for creating and managing a visible window for a view.
- @{
+ Set the transient parent of the window.
+
+ This is used for things like dialogs, to have them associated with the
+ window they are a transient child of properly.
*/
+PUGL_API PuglStatus
+puglSetTransientFor(PuglView* view, PuglNativeWindow parent);
/**
Create a window with the settings given by the various puglInit functions.
@return 1 (pugl does not currently support multiple windows).
*/
-PUGL_API int
+PUGL_API PuglStatus
puglCreateWindow(PuglView* view, const char* title);
/**
Show the current window.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglShowWindow(PuglView* view);
/**
Hide the current window.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglHideWindow(PuglView* view);
/**
@@ -541,40 +667,37 @@ puglGetNativeWindow(PuglView* view);
/**
@}
+ @name Graphics Context
+ Functions for working with the drawing context.
+ @{
*/
/**
- Set the handle to be passed to all callbacks.
-
- This is generally a pointer to a struct which contains all necessary state.
- Everything needed in callbacks should be here, not in static variables.
+ Graphics backend interface.
*/
-PUGL_API void
-puglSetHandle(PuglView* view, PuglHandle handle);
+typedef struct PuglBackendImpl PuglBackend;
/**
- Get the handle to be passed to all callbacks.
+ OpenGL extension function.
*/
-PUGL_API PuglHandle
-puglGetHandle(PuglView* view);
+typedef void (*PuglGlFunc)(void);
/**
- Return true iff the view is currently visible.
-*/
-PUGL_API bool
-puglGetVisible(PuglView* view);
+ Set the graphics backend to use.
-/**
- Get the current size of the view.
+ This needs to be called once before creating the window to set the graphics
+ backend. There are two backend accessors included with pugl:
+ puglGlBackend() and puglCairoBackend(), declared in pugl_gl_backend.h and
+ pugl_cairo_backend.h, respectively.
*/
-PUGL_API void
-puglGetSize(PuglView* view, int* width, int* height);
+PUGL_API PuglStatus
+puglSetBackend(PuglView* view, const PuglBackend* backend);
/**
- @name Context
- Functions for accessing the drawing context.
- @{
+ Return the address of an OpenGL extension function.
*/
+PUGL_API PuglGlFunc
+puglGetProcAddress(const char* name);
/**
Get the drawing context.
@@ -598,7 +721,7 @@ puglGetContext(PuglView* view);
@param view The view being entered.
@param drawing If true, prepare for drawing.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglEnterContext(PuglView* view, bool drawing);
/**
@@ -610,109 +733,287 @@ puglEnterContext(PuglView* view, bool drawing);
@param view The view being left.
@param drawing If true, finish drawing, for example by swapping buffers.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglLeaveContext(PuglView* view, bool drawing);
/**
@}
- @name Event Handling
+ @anchor interaction
+ @name Interaction
+ Interacting with the system and user with events.
@{
*/
/**
A function called when an event occurs.
*/
-typedef void (*PuglEventFunc)(PuglView* view, const PuglEvent* event);
+typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event);
/**
Set the function to call when an event occurs.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc);
/**
- Ignore synthetic repeated key events.
-
- @deprecated Use puglInitWindowHint() with @ref PUGL_IGNORE_KEY_REPEAT.
+ Return true iff `view` has the input focus.
*/
-PUGL_API PUGL_DEPRECATED_BY("puglInitWindowHint") void
-puglIgnoreKeyRepeat(PuglView* view, bool ignore);
+PUGL_API bool
+puglHasFocus(const PuglView* view);
/**
Grab the input focus.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglGrabFocus(PuglView* view);
/**
+ Get clipboard contents.
+
+ @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);
+
+/**
+ Set clipboard contents.
+
+ @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 PuglStatus
+puglSetClipboard(PuglView* view,
+ const char* type,
+ const void* data,
+ size_t len);
+
+/**
Request user attention.
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 flashing a task bar entry.
*/
-PUGL_API void
+PUGL_API PuglStatus
puglRequestAttention(PuglView* view);
/**
- Block and wait for an event to be ready.
+ @}
+ @name Deprecated API
+ @{
+*/
- This can be used in a loop to only process events via puglProcessEvents when
- 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).
+#if defined(__clang__)
+# define PUGL_DEPRECATED_BY(name) __attribute__((deprecated("", name)))
+#elif defined(__GNUC__)
+# define PUGL_DEPRECATED_BY(name) __attribute__((deprecated("Use " name)))
+#else
+# define PUGL_DEPRECATED_BY(name)
+#endif
+
+/**
+ Create a Pugl application and view.
+
+ To create a window, call the various puglInit* functions as necessary, then
+ call puglCreateWindow().
+
+ @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 PuglStatus
-puglWaitForEvent(PuglView* view);
+static inline PUGL_DEPRECATED_BY("puglNewView") PuglView*
+puglInit(const int* pargc, char** argv)
+{
+ (void)pargc;
+ (void)argv;
+
+ return puglNewView(puglNewWorld());
+}
/**
- Process all pending window events.
+ Destroy an app and view created with `puglInit()`.
- 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 puglFreeApp() and puglFreeView().
*/
-PUGL_API PuglStatus
-puglProcessEvents(PuglView* view);
+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);
+}
/**
- OpenGL extension function.
+ Set the window size before creating a window.
+
+ @deprecated Use puglSetFrame().
*/
-typedef void (*PuglGlFunc)(void);
+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);
+}
/**
- Return the address of an OpenGL extension function.
+ Set the minimum window size before creating a window.
*/
-PUGL_API PuglGlFunc
-puglGetProcAddress(const char* name);
+static inline PUGL_DEPRECATED_BY("puglSetMinSize") void
+puglInitWindowMinSize(PuglView* view, int width, int height)
+{
+ puglSetMinSize(view, width, height);
+}
/**
- Return the time in seconds.
+ Set the window aspect ratio range before creating a window.
- 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.
+ 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.
*/
-PUGL_API double
-puglGetTime(PuglView* view);
+static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") void
+puglInitWindowAspectRatio(PuglView* view,
+ int minX,
+ int minY,
+ int maxX,
+ int maxY)
+{
+ puglSetAspectRatio(view, minX, minY, maxX, maxY);
+}
/**
- Request a redisplay on the next call to puglProcessEvents().
+ Set transient parent before creating a window.
+
+ On X11, parent must be a Window.
+ On OSX, parent must be an NSView*.
*/
-PUGL_API void
-puglPostRedisplay(PuglView* view);
+static inline PUGL_DEPRECATED_BY("puglSetTransientFor") void
+puglInitTransientFor(PuglView* view, uintptr_t parent)
+{
+ puglSetTransientFor(view, (PuglNativeWindow)parent);
+}
/**
- Destroy a GL window.
+ Enable or disable resizing before creating a window.
+
+ @deprecated Use puglSetViewHint() with @ref PUGL_RESIZABLE.
*/
-PUGL_API void
-puglDestroy(PuglView* view);
+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 @ref PUGL_IGNORE_KEY_REPEAT.
+*/
+static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
+puglIgnoreKeyRepeat(PuglView* view, bool ignore)
+{
+ puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, ignore);
+}
+
+/**
+ Set a hint before creating a window.
+
+ @deprecated Use puglSetWindowHint().
+*/
+static inline PUGL_DEPRECATED_BY("puglSetViewHint") void
+puglInitWindowHint(PuglView* view, PuglViewHint hint, int value)
+{
+ puglSetViewHint(view, hint, value);
+}
+
+/**
+ Set the parent window before creating a window (for embedding).
+
+ @deprecated Use puglSetWindowParent().
+*/
+static inline PUGL_DEPRECATED_BY("puglSetParentWindow") void
+puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
+{
+ puglSetParentWindow(view, parent);
+}
+
+/**
+ Set the graphics backend to use.
+
+ @deprecated Use puglSetBackend().
+*/
+static inline PUGL_DEPRECATED_BY("puglSetBackend") int
+puglInitBackend(PuglView* view, const PuglBackend* backend)
+{
+ return puglSetBackend(view, backend);
+}
+
+/**
+ Block and wait for an event to be ready.
+
+ This can be used in a loop to only process events via puglProcessEvents when
+ 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 PUGL_DEPRECATED_BY("puglPollEvents") PuglStatus
+puglWaitForEvent(PuglView* view);
+
+/**
+ Process all pending window events.
+
+ 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 PUGL_DEPRECATED_BY("puglDispatchEvents") PuglStatus
+puglProcessEvents(PuglView* view);
+
+/**
+ @}
@}
*/
diff --git a/pugl/pugl/pugl.hpp b/pugl/pugl/pugl.hpp
index c2602dd..dee8c17 100644
--- a/pugl/pugl/pugl.hpp
+++ b/pugl/pugl/pugl.hpp
@@ -15,7 +15,7 @@
*/
/**
- @file pugl.hpp Public Pugl C++ API wrapper.
+ @file pugl.hpp Pugl C++ API wrapper.
*/
#ifndef PUGL_HPP_INCLUDED
@@ -25,7 +25,7 @@
/**
@defgroup puglmm Puglmm
- C++ API wrapper for Pugl.
+ Pugl C++ API wrapper.
@{
*/
diff --git a/pugl/test/glad/glad.c b/pugl/test/glad/glad.c
new file mode 100644
index 0000000..2a0567c
--- /dev/null
+++ b/pugl/test/glad/glad.c
@@ -0,0 +1,1016 @@
+/*
+
+ OpenGL loader generated by glad 0.1.32 on -.
+
+ Language/Generator: C/C++
+ Specification: gl
+ APIs: gl=3.2
+ Profile: core
+ Extensions:
+
+ Loader: True
+ Local files: True
+ Omit khrplatform: False
+ Reproducible: True
+
+ Commandline:
+ --profile="core" --api="gl=3.2" --generator="c" --spec="gl" --local-files --extensions=""
+ Online:
+ https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.2
+*/
+
+#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;
+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;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = 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;
+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;
+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;
+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;
+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;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = 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;
+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;
+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;
+PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
+PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
+PFNGLSCISSORPROC glad_glScissor = 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;
+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;
+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;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = 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 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;
+ if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 2)) {
+ max_loaded_major = 3;
+ max_loaded_minor = 2;
+ }
+}
+
+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);
+
+ if (!find_extensionsGL()) return 0;
+ return GLVersion.major != 0 || GLVersion.minor != 0;
+}
+
diff --git a/pugl/test/glad/glad.h b/pugl/test/glad/glad.h
new file mode 100644
index 0000000..b743679
--- /dev/null
+++ b/pugl/test/glad/glad.h
@@ -0,0 +1,1935 @@
+/*
+
+ OpenGL loader generated by glad 0.1.32 on -.
+
+ Language/Generator: C/C++
+ Specification: gl
+ APIs: gl=3.2
+ Profile: core
+ Extensions:
+
+ Loader: True
+ Local files: True
+ Omit khrplatform: False
+ Reproducible: True
+
+ Commandline:
+ --profile="core" --api="gl=3.2" --generator="c" --spec="gl" --local-files --extensions=""
+ Online:
+ https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.2
+*/
+
+
+#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
+#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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pugl/test/glad/khrplatform.h b/pugl/test/glad/khrplatform.h
new file mode 100644
index 0000000..5b55ea2
--- /dev/null
+++ b/pugl/test/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/pugl/test/pugl_cairo_test.c b/pugl/test/pugl_cairo_test.c
index a16c821..23c2b4e 100644
--- a/pugl/test/pugl_cairo_test.c
+++ b/pugl/test/pugl_cairo_test.c
@@ -30,7 +30,9 @@
#include <stdio.h>
#include <string.h>
-static bool continuous = false;
+static PuglWorld* world = NULL;
+PuglTestOptions opts = {0};
+
static int quit = 0;
static bool entered = false;
static bool mouseDown = false;
@@ -113,8 +115,9 @@ onDisplay(PuglView* view)
cairo_t* cr = (cairo_t*)puglGetContext(view);
// Draw background
- int width, height;
- puglGetSize(view, &width, &height);
+ const PuglRect frame = puglGetFrame(view);
+ const double width = frame.width;
+ const double height = frame.height;
if (entered) {
cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
} else {
@@ -124,13 +127,13 @@ onDisplay(PuglView* view)
cairo_fill(cr);
// Scale to view size
- const double scaleX = (width - (512 / (double)width)) / 512.0;
- const double scaleY = (height - (512 / (double)height)) / 512.0;
+ const double scaleX = (width - (512 / width)) / 512.0;
+ const double scaleY = (height - (512 / height)) / 512.0;
cairo_scale(cr, scaleX, scaleY);
// Draw button
for (Button* b = buttons; b->label; ++b) {
- buttonDraw(cr, b, continuous ? puglGetTime(view) : 0.0);
+ buttonDraw(cr, b, opts.continuous ? puglGetTime(world) : 0.0);
}
++framesDrawn;
@@ -143,7 +146,7 @@ onClose(PuglView* view)
quit = 1;
}
-static void
+static PuglStatus
onEvent(PuglView* view, const PuglEvent* event)
{
switch (event->type) {
@@ -176,40 +179,30 @@ onEvent(PuglView* view, const PuglEvent* event)
break;
default: break;
}
+
+ return PUGL_SUCCESS;
}
int
main(int argc, char** argv)
{
- bool ignoreKeyRepeat = false;
- bool resizable = false;
- for (int i = 1; i < argc; ++i) {
- if (!strcmp(argv[i], "-c")) {
- continuous = true;
- } else if (!strcmp(argv[i], "-h")) {
- printf("USAGE: %s [OPTIONS]...\n\n"
- " -c Continuously animate and draw\n"
- " -h Display this help\n"
- " -i Ignore key repeat\n"
- " -r Resizable window\n", argv[0]);
- return 0;
- } else if (!strcmp(argv[i], "-i")) {
- ignoreKeyRepeat = true;
- } else if (!strcmp(argv[i], "-r")) {
- resizable = true;
- } else {
- fprintf(stderr, "Unknown option: %s\n", argv[i]);
- }
+ opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage("pugl_test", "");
+ return 1;
}
- PuglView* view = puglInit(NULL, NULL);
- puglInitWindowClass(view, "PuglCairoTest");
- puglInitWindowSize(view, 512, 512);
- puglInitWindowMinSize(view, 256, 256);
- puglInitWindowHint(view, PUGL_RESIZABLE, resizable);
- puglInitBackend(view, puglCairoBackend());
+ world = puglNewWorld();
+ puglSetClassName(world, "PuglCairoTest");
+
+ PuglRect frame = { 0, 0, 512, 512 };
+ PuglView* view = puglNewView(world);
+ puglSetFrame(view, frame);
+ puglSetMinSize(view, 256, 256);
+ puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable);
+ puglSetBackend(view, puglCairoBackend());
- puglInitWindowHint(view, PUGL_IGNORE_KEY_REPEAT, ignoreKeyRepeat);
+ puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat);
puglSetEventFunc(view, onEvent);
if (puglCreateWindow(view, "Pugl Test")) {
@@ -218,21 +211,22 @@ main(int argc, char** argv)
puglShowWindow(view);
- PuglFpsPrinter fpsPrinter = { puglGetTime(view) };
+ PuglFpsPrinter fpsPrinter = { puglGetTime(world) };
while (!quit) {
- if (continuous) {
+ if (opts.continuous) {
puglPostRedisplay(view);
} else {
- puglWaitForEvent(view);
+ puglPollEvents(world, -1);
}
- puglProcessEvents(view);
+ puglDispatchEvents(world);
- if (continuous) {
- puglPrintFps(view, &fpsPrinter, &framesDrawn);
+ if (opts.continuous) {
+ puglPrintFps(world, &fpsPrinter, &framesDrawn);
}
}
- puglDestroy(view);
+ puglFreeView(view);
+ puglFreeWorld(world);
return 0;
}
diff --git a/pugl/test/pugl_gl3_test.c b/pugl/test/pugl_gl3_test.c
new file mode 100644
index 0000000..f2d77f9
--- /dev/null
+++ b/pugl/test/pugl_gl3_test.c
@@ -0,0 +1,395 @@
+/*
+ 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_gl3_test.c A simple test of OpenGL 3 with Pugl.
+
+ 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, with one draw call per
+ rectangle (the shader draws the borders). Rectangle attributes are
+ controlled via uniform variables. This is certainly not the fastest way to
+ do this: it is probably CPU and/or I/O bound, but serves as a decent very
+ rough benchmark for how many draw calls you can get away with.
+
+ A better (if slightly more GPU memory intensive) way to do this would be to
+ put everything in vertex attributes, jam all the rectangle data into a
+ single buffer, and draw the whole thing with a single draw call. That way
+ would probably be GPU bound instead, and show a difference between alpha
+ blending and depth testing for many overlapped rectangles.
+*/
+
+#define GL_SILENCE_DEPRECATION 1
+
+#include "shader_utils.h"
+#include "test_utils.h"
+
+#include "glad/glad.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.h"
+#include "pugl/pugl_gl_backend.h"
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.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];
+ float borderColor[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};
+
+/* The vertex shader is trivial, but forwards scaled UV coordinates (in pixels)
+ to the fragment shader for drawing the border. */
+static const char* vertexSource = //
+ "#version 330\n"
+ "uniform mat4 MVP;\n"
+ "uniform vec2 u_size;\n"
+ "in vec2 v_position;\n"
+ "noperspective out vec2 f_uv;\n"
+ "void main() {\n"
+ " f_uv = v_position * u_size;\n"
+ " gl_Position = MVP * vec4(v_position, 0.0, 1.0);\n"
+ "}\n";
+
+/* The fragment shader uses the UV coordinates to calculate whether it is in
+ the T, R, B, or L border. These are then mixed with the border color, and
+ their inverse is mixed with the fill color, to calculate the fragment color.
+ For example, if we are in the top border, then T=1, so the border mix factor
+ TRBL=1, and the fill mix factor (1-TRBL) is 0.
+
+ The use of pixel units here is handy because the border width can be
+ specified precisely in pixels to draw sharp lines. The border width is just
+ hardcoded, but code be made a uniform or vertex attribute easily enough. */
+static const char* fragmentSource = //
+ "#version 330\n"
+ "uniform vec2 u_size;\n"
+ "uniform vec4 u_borderColor;\n"
+ "uniform vec4 u_fillColor;\n"
+ "noperspective in vec2 f_uv;\n"
+ "layout(location = 0) out vec4 FragColor;\n"
+ "void main() {\n"
+ " const float border_width = 2.0;\n"
+ "\n"
+ " float t = step(border_width, f_uv[1]);\n"
+ " float r = step(border_width, u_size.x - f_uv[0]);\n"
+ " float b = step(border_width, u_size.y - f_uv[1]);\n"
+ " float l = step(border_width, f_uv[0]);\n"
+ " float fill_mix = t * r * b * l;\n"
+ " float border_mix = 1.0 - fill_mix;\n"
+ " vec4 fill = fill_mix * u_fillColor;\n"
+ " vec4 border = border_mix * u_borderColor;\n"
+ " FragColor = fill + border;\n"
+ "}\n";
+
+typedef struct
+{
+ PuglTestOptions opts;
+ PuglWorld* world;
+ PuglView* view;
+ size_t numRects;
+ Rect* rects;
+ Program drawRect;
+ GLuint vao;
+ GLuint vbo;
+ GLuint ibo;
+ GLint u_MVP;
+ GLint u_size;
+ GLint u_fillColor;
+ GLint u_borderColor;
+ unsigned framesDrawn;
+ int quit;
+} PuglTestApp;
+
+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
+drawRect(const PuglTestApp* app, const Rect* rect, mat4 projection)
+{
+ /* The vertex data is always the same: a normalized rectangle from (0, 0)
+ to (1, 1). We use the MVP matrix to scale and translate this to the
+ desired screen coordinates. */
+
+ // Construct model matrix to scale/translate to screen coordinates
+ mat4 m;
+ mat4Identity(m);
+ mat4Translate(m, rect->pos[0], rect->pos[1], 0);
+ m[0][0] = rect->size[0];
+ m[1][1] = rect->size[1];
+
+ // Combine them into the final MVP matrix and set uniform
+ mat4 mvp;
+ mat4Mul(mvp, projection, m);
+ glUniformMatrix4fv(app->u_MVP, 1, GL_FALSE, (const GLfloat*)&mvp);
+
+ // Set uniforms for the various rectangle attributes
+ glUniform2fv(app->u_size, 1, rect->size);
+ glUniform4fv(app->u_fillColor, 1, rect->fillColor);
+ glUniform4fv(app->u_borderColor, 1, rect->borderColor);
+
+ // Draw
+ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
+}
+
+static void
+onExpose(PuglView* view)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+ const PuglRect frame = puglGetFrame(view);
+ 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);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app->ibo);
+
+ for (size_t i = 0; i < app->numRects; ++i) {
+ Rect* rect = &app->rects[i];
+
+ // Move rect around in an arbitrary way that looks cool
+ rect->pos[0] = (float)(frame.width - rect->size[0]) *
+ (sinf((float)time * rect->size[0] / 100.0f) + 1.0f) /
+ 2.0f;
+ rect->pos[1] = (float)(frame.height - rect->size[1]) *
+ (cosf((float)time * rect->size[1] / 100.0f) + 1.0f) /
+ 2.0f;
+
+ drawRect(app, rect, proj);
+ }
+
+ ++app->framesDrawn;
+}
+
+static PuglStatus
+onEvent(PuglView* view, const PuglEvent* event)
+{
+ PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
+
+ printEvent(event, "Event: ");
+
+ switch (event->type) {
+ case PUGL_CONFIGURE:
+ onConfigure(view, event->configure.width, event->configure.height);
+ 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 int width, const int height)
+{
+ const int minSize = width / 32;
+ const int maxSize = width / 4;
+ const float boxAlpha = 0.6f;
+
+ Rect* rects = (Rect*)calloc(numRects, sizeof(Rect));
+ for (size_t i = 0; i < numRects; ++i) {
+ rects[i].pos[0] = (float)(rand() % width);
+ rects[i].pos[1] = (float)(rand() % height);
+ rects[i].size[0] = (float)minSize + rand() % (maxSize - minSize);
+ rects[i].size[1] = (float)minSize + rand() % (maxSize - minSize);
+
+ rects[i].fillColor[1] = (rand() % numRects) / ((float)numRects - 0.4f);
+ rects[i].fillColor[2] = (rand() % numRects) / ((float)numRects - 0.4f);
+ rects[i].fillColor[3] = boxAlpha;
+
+ rects[i].borderColor[1] = rects[i].fillColor[1] + 0.4f;
+ rects[i].borderColor[2] = rects[i].fillColor[1] + 0.4f;
+ rects[i].borderColor[3] = boxAlpha;
+ }
+
+ return rects;
+}
+
+int
+main(int argc, char** argv)
+{
+ PuglTestApp app;
+ memset(&app, 0, sizeof(app));
+
+ const PuglRect frame = {0, 0, defaultWidth, defaultHeight};
+
+ // Parse command line options
+ app.numRects = 1024;
+ app.opts = puglParseTestOptions(&argc, &argv);
+ if (app.opts.help) {
+ puglPrintTestUsage("pugl_gl3_test", "[NUM_RECTS]");
+ 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])) {
+ puglPrintTestUsage("pugl_gl3_test", "[NUM_RECTS]");
+ return 1;
+ }
+ }
+
+ // Create world, view, and rect data
+ app.world = puglNewWorld();
+ app.view = puglNewView(app.world);
+ app.rects = makeRects(app.numRects, defaultWidth, defaultHeight);
+
+ // Set up world and view
+ puglSetClassName(app.world, "PuglGL3Test");
+ 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_TRUE);
+ 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.doubleBuffer);
+ puglSetViewHint(app.view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE);
+ puglSetHandle(app.view, &app);
+ puglSetEventFunc(app.view, onEvent);
+
+ if (puglCreateWindow(app.view, "Pugl OpenGL 3")) {
+ fprintf(stderr, "error: Failed to create window window\n");
+ return 1;
+ }
+
+ // Enter context to set up GL stuff
+ puglEnterContext(app.view, false);
+
+ // Load GL functions via GLAD
+ if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) {
+ fprintf(stderr, "error: Failed to load GL\n");
+ puglFreeView(app.view);
+ puglFreeWorld(app.world);
+ return 1;
+ }
+
+ // Compile rectangle shaders and program
+ app.drawRect = compileProgram(vertexSource, fragmentSource);
+ if (!app.drawRect.program) {
+ puglFreeView(app.view);
+ puglFreeWorld(app.world);
+ return 1;
+ }
+
+ // Get location of rectangle shader uniforms
+ app.u_MVP = glGetUniformLocation(app.drawRect.program, "MVP");
+ app.u_size = glGetUniformLocation(app.drawRect.program, "u_size");
+ app.u_fillColor = glGetUniformLocation(app.drawRect.program, "u_fillColor");
+ app.u_borderColor =
+ glGetUniformLocation(app.drawRect.program, "u_borderColor");
+
+ // 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);
+
+ // Set up the first/only attribute, position, as 2 floats from the VBO
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL);
+
+ // 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);
+
+ // Finally ready to go, leave GL context and show the window
+ puglLeaveContext(app.view, false);
+ puglShowWindow(app.view);
+
+ // Grind away, drawing continuously
+ PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
+ while (!app.quit) {
+ puglPostRedisplay(app.view);
+ puglDispatchEvents(app.world);
+ puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn);
+ }
+
+ // Delete GL stuff
+ puglEnterContext(app.view, false);
+ glDeleteBuffers(1, &app.ibo);
+ glDeleteBuffers(1, &app.vbo);
+ glDeleteVertexArrays(1, &app.vao);
+ deleteProgram(app.drawRect);
+ puglLeaveContext(app.view, false);
+
+ // Tear down view and world
+ puglFreeView(app.view);
+ puglFreeWorld(app.world);
+ return 0;
+}
diff --git a/pugl/test/pugl_test.c b/pugl/test/pugl_test.c
index b8a0a42..4bd5f80 100644
--- a/pugl/test/pugl_test.c
+++ b/pugl/test/pugl_test.c
@@ -32,20 +32,38 @@
#include <stdio.h>
#include <string.h>
+static const int borderWidth = 64;
+
typedef struct
{
- bool continuous;
- int quit;
- float xAngle;
- float yAngle;
- float dist;
- double lastMouseX;
- double lastMouseY;
- double lastDrawTime;
- unsigned framesDrawn;
- bool mouseEntered;
+ PuglWorld* world;
+ PuglView* parent;
+ PuglView* child;
+ bool continuous;
+ int quit;
+ float xAngle;
+ float yAngle;
+ float dist;
+ double lastMouseX;
+ double lastMouseY;
+ double lastDrawTime;
+ unsigned framesDrawn;
+ bool mouseEntered;
} PuglTestApp;
+static PuglRect
+getChildFrame(const PuglRect parentFrame)
+{
+ const PuglRect childFrame = {
+ borderWidth,
+ borderWidth,
+ parentFrame.width - 2 * borderWidth,
+ parentFrame.height - 2 * borderWidth
+ };
+
+ return childFrame;
+}
+
static void
onReshape(PuglView* view, int width, int height)
{
@@ -69,7 +87,7 @@ onDisplay(PuglView* view)
{
PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
- const double thisTime = puglGetTime(view);
+ const double thisTime = puglGetTime(app->world);
if (app->continuous) {
const double dTime = thisTime - app->lastDrawTime;
app->xAngle = fmodf((float)(app->xAngle + dTime * 100.0f), 360.0f);
@@ -82,29 +100,154 @@ onDisplay(PuglView* view)
glRotatef(app->xAngle, 0.0f, 1.0f, 0.0f);
glRotatef(app->yAngle, 1.0f, 0.0f, 0.0f);
- const float bg = app->mouseEntered ? 0.2f : 0.0f;
+ const float bg = app->mouseEntered ? 0.2f : 0.1f;
glClearColor(bg, bg, bg, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
- glColorPointer(3, GL_FLOAT, 0, cubeVertices);
- glDrawArrays(GL_TRIANGLES, 0, 12 * 3);
+ if (puglHasFocus(app->child)) {
+ // 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);
- glDisableClientState(GL_COLOR_ARRAY);
app->lastDrawTime = thisTime;
++app->framesDrawn;
}
static void
+swapFocus(PuglTestApp* app)
+{
+ if (puglHasFocus(app->parent)) {
+ puglGrabFocus(app->child);
+ } else {
+ puglGrabFocus(app->parent);
+ }
+
+ 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: ");
+
+ switch (event->type) {
+ case PUGL_CONFIGURE:
+ onReshape(view,
+ (int)event->configure.width,
+ (int)event->configure.height);
+
+ puglSetFrame(app->child, getChildFrame(parentFrame));
+ 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, cubeStripVertices);
+ glColorPointer(3, GL_FLOAT, 0, cubeStripVertices);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 14);
+ 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_NOTIFY:
+ 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, "Event: ");
+ printEvent(event, "Child: ");
switch (event->type) {
case PUGL_CONFIGURE:
@@ -117,9 +260,7 @@ onEvent(PuglView* view, const PuglEvent* event)
app->quit = 1;
break;
case PUGL_KEY_PRESS:
- if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
- app->quit = 1;
- }
+ onKeyPress(view, &event->key, "Child: ");
break;
case PUGL_MOTION_NOTIFY:
app->xAngle = fmodf(app->xAngle - (float)(event->motion.x - app->lastMouseX), 360.0f);
@@ -127,6 +268,7 @@ onEvent(PuglView* view, const PuglEvent* event)
app->lastMouseX = event->motion.x;
app->lastMouseY = event->motion.y;
puglPostRedisplay(view);
+ puglPostRedisplay(app->parent);
break;
case PUGL_SCROLL:
app->dist = fmaxf(10.0f, app->dist + (float)event->scroll.dy);
@@ -141,6 +283,8 @@ onEvent(PuglView* view, const PuglEvent* event)
default:
break;
}
+
+ return PUGL_SUCCESS;
}
int
@@ -149,81 +293,88 @@ main(int argc, char** argv)
PuglTestApp app = {0};
app.dist = 10;
- int samples = 0;
- int doubleBuffer = PUGL_FALSE;
- bool ignoreKeyRepeat = false;
- bool resizable = false;
- for (int i = 1; i < argc; ++i) {
- if (!strcmp(argv[i], "-a")) {
- samples = 4;
- } else if (!strcmp(argv[i], "-c")) {
- app.continuous = true;
- } else if (!strcmp(argv[i], "-d")) {
- doubleBuffer = PUGL_TRUE;
- } else if (!strcmp(argv[i], "-h")) {
- printf("USAGE: %s [OPTIONS]...\n\n"
- " -a Enable anti-aliasing\n"
- " -c Continuously animate and draw\n"
- " -d Enable double-buffering\n"
- " -h Display this help\n"
- " -i Ignore key repeat\n"
- " -r Resizable window\n", argv[0]);
- return 0;
- } else if (!strcmp(argv[i], "-i")) {
- ignoreKeyRepeat = true;
- } else if (!strcmp(argv[i], "-r")) {
- resizable = true;
- } else {
- fprintf(stderr, "Unknown option: %s\n", argv[i]);
- }
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage("pugl_test", "");
+ return 1;
}
- PuglView* view = puglInit(NULL, NULL);
- puglInitWindowClass(view, "PuglTest");
- puglInitWindowSize(view, 512, 512);
- puglInitWindowMinSize(view, 256, 256);
- puglInitWindowAspectRatio(view, 1, 1, 16, 9);
- puglInitBackend(view, puglGlBackend());
+ app.continuous = opts.continuous;
+
+ app.world = puglNewWorld();
+ app.parent = puglNewView(app.world);
+ app.child = puglNewView(app.world);
- puglInitWindowHint(view, PUGL_RESIZABLE, resizable);
- puglInitWindowHint(view, PUGL_SAMPLES, samples);
- puglInitWindowHint(view, PUGL_DOUBLE_BUFFER, doubleBuffer);
+ puglSetClassName(app.world, "Pugl Test");
- puglInitWindowHint(view, PUGL_IGNORE_KEY_REPEAT, ignoreKeyRepeat);
- puglSetEventFunc(view, onEvent);
- puglSetHandle(view, &app);
+ 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_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.doubleBuffer);
+ puglSetViewHint(app.parent, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat);
+ puglSetHandle(app.parent, &app);
+ puglSetEventFunc(app.parent, onParentEvent);
const uint8_t title[] = { 'P', 'u', 'g', 'l', ' ',
'P', 'r', 0xC3, 0xBC, 'f', 'u', 'n', 'g', 0 };
- if (puglCreateWindow(view, (const char*)title)) {
+ if (puglCreateWindow(app.parent, (const char*)title)) {
+ fprintf(stderr, "error: Failed to create parent window\n");
return 1;
}
- puglShowWindow(view);
+ puglSetFrame(app.child, getChildFrame(parentFrame));
+ puglSetParentWindow(app.child, puglGetNativeWindow(app.parent));
+
+ puglSetViewHint(app.child, PUGL_SAMPLES, opts.samples);
+ puglSetViewHint(app.child, PUGL_DOUBLE_BUFFER, opts.doubleBuffer);
+ puglSetViewHint(app.child, PUGL_SWAP_INTERVAL, 0);
+ puglSetBackend(app.child, puglGlBackend());
+ puglSetViewHint(app.child, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat);
+ puglSetHandle(app.child, &app);
+ puglSetEventFunc(app.child, onEvent);
- PuglFpsPrinter fpsPrinter = { puglGetTime(view) };
+ const int st = puglCreateWindow(app.child, NULL);
+ if (st) {
+ fprintf(stderr, "error: Failed to create child window (%d)\n", st);
+ return 1;
+ }
+
+ puglShowWindow(app.parent);
+ puglShowWindow(app.child);
+
+ PuglFpsPrinter fpsPrinter = { puglGetTime(app.world) };
bool requestedAttention = false;
while (!app.quit) {
- const double thisTime = puglGetTime(view);
+ const double thisTime = puglGetTime(app.world);
if (app.continuous) {
- puglPostRedisplay(view);
+ puglPostRedisplay(app.parent);
+ puglPostRedisplay(app.child);
} else {
- puglWaitForEvent(view);
+ puglPollEvents(app.world, -1);
}
- puglProcessEvents(view);
+ puglDispatchEvents(app.world);
if (!requestedAttention && thisTime > 5.0) {
- puglRequestAttention(view);
+ puglRequestAttention(app.parent);
requestedAttention = true;
}
if (app.continuous) {
- puglPrintFps(view, &fpsPrinter, &app.framesDrawn);
+ puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn);
}
}
- puglDestroy(view);
+ puglFreeView(app.child);
+ puglFreeView(app.parent);
+ puglFreeWorld(app.world);
+
return 0;
}
diff --git a/pugl/test/shader_utils.h b/pugl/test/shader_utils.h
new file mode 100644
index 0000000..834d8fc
--- /dev/null
+++ b/pugl/test/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/pugl/test/test_utils.h b/pugl/test/test_utils.h
index 9738d96..8e9c7ff 100644
--- a/pugl/test/test_utils.h
+++ b/pugl/test/test_utils.h
@@ -19,60 +19,123 @@
#include <math.h>
#include <stdint.h>
#include <stdio.h>
+#include <string.h>
typedef struct {
double lastReportTime;
} PuglFpsPrinter;
-static const float cubeVertices[] = {
- -1.0f, -1.0f, -1.0f,
- -1.0f, -1.0f, 1.0f,
- -1.0f, 1.0f, 1.0f,
+typedef struct {
+ int samples;
+ int doubleBuffer;
+ bool continuous;
+ bool help;
+ bool ignoreKeyRepeat;
+ bool resizable;
+} PuglTestOptions;
- 1.0f, 1.0f, -1.0f,
- -1.0f, -1.0f, -1.0f,
- -1.0f, 1.0f, -1.0f,
+typedef float vec4[4];
+typedef vec4 mat4[4];
- 1.0f, -1.0f, 1.0f,
- -1.0f, -1.0f, -1.0f,
- 1.0f, -1.0f, -1.0f,
+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
+};
- 1.0f, 1.0f, -1.0f,
- 1.0f, -1.0f, -1.0f,
- -1.0f, -1.0f, -1.0f,
+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
+};
- -1.0f, -1.0f, -1.0f,
- -1.0f, 1.0f, 1.0f,
- -1.0f, 1.0f, -1.0f,
+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
+};
- 1.0f, -1.0f, 1.0f,
- -1.0f, -1.0f, 1.0f,
- -1.0f, -1.0f, -1.0f,
+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,
- -1.0f, -1.0f, 1.0f,
- 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f, // Front bottom left
+ -1.0f, -1.0f, -1.0f, // Back bottom left
- 1.0f, 1.0f, 1.0f,
- 1.0f, -1.0f, -1.0f,
- 1.0f, 1.0f, -1.0f,
+ 1.0f, 1.0f, 1.0f, // Front top right
+ 1.0f, 1.0f, -1.0f, // Back top right
- 1.0f, -1.0f, -1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, // Front bottom right
+ 1.0f, -1.0f, -1.0f, // Back bottom right
+};
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, -1.0f,
- -1.0f, 1.0f, -1.0f,
+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;
+ }
+ }
+}
- 1.0f, 1.0f, 1.0f,
- -1.0f, 1.0f, -1.0f,
- -1.0f, 1.0f, 1.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;
+}
- 1.0f, 1.0f, 1.0f,
- -1.0f, 1.0f, 1.0f,
- 1.0f, -1.0f, 1.0f
-};
+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
@@ -148,11 +211,59 @@ printEvent(const PuglEvent* event, const char* prefix)
}
static inline void
-puglPrintFps(PuglView* view,
- PuglFpsPrinter* printer,
- unsigned* const framesDrawn)
+puglPrintTestUsage(const char* prog, const char* posHelp)
+{
+ printf("Usage: %s [OPTION]... %s\n\n"
+ " -a Enable anti-aliasing\n"
+ " -c Continuously animate and draw\n"
+ " -d Enable double-buffering\n"
+ " -h Display this help\n"
+ " -i Ignore key repeat\n"
+ " -r Resizable window\n",
+ prog, posHelp);
+}
+
+static inline PuglTestOptions
+puglParseTestOptions(int* pargc, char*** pargv)
+{
+ PuglTestOptions opts = { 0, 0, false, false, false, false };
+
+ char** const argv = *pargv;
+ int i = 1;
+ for (; i < *pargc; ++i) {
+ if (!strcmp(argv[i], "-a")) {
+ opts.samples = 4;
+ } else if (!strcmp(argv[i], "-c")) {
+ opts.continuous = true;
+ } else if (!strcmp(argv[i], "-d")) {
+ opts.doubleBuffer = PUGL_TRUE;
+ } else if (!strcmp(argv[i], "-h")) {
+ opts.help = true;
+ return opts;
+ } else if (!strcmp(argv[i], "-i")) {
+ opts.ignoreKeyRepeat = true;
+ } else if (!strcmp(argv[i], "-r")) {
+ opts.resizable = true;
+ } else if (argv[i][0] != '-') {
+ break;
+ } else {
+ opts.help = true;
+ fprintf(stderr, "error: Unknown option: %s\n", argv[i]);
+ }
+ }
+
+ *pargc -= i;
+ *pargv += i;
+
+ return opts;
+}
+
+static inline void
+puglPrintFps(const PuglWorld* world,
+ PuglFpsPrinter* printer,
+ unsigned* const framesDrawn)
{
- const double thisTime = puglGetTime(view);
+ const double thisTime = puglGetTime(world);
if (thisTime > printer->lastReportTime + 5) {
const double fps = *framesDrawn / (thisTime - printer->lastReportTime);
fprintf(stderr,
diff --git a/pugl/wscript b/pugl/wscript
index 796a9ce..5fce00e 100644
--- a/pugl/wscript
+++ b/pugl/wscript
@@ -55,7 +55,7 @@ def configure(conf):
for f in ('CFLAGS', 'CXXFLAGS'):
conf.env.append_value(f, ['-fvisibility=hidden'])
if Options.options.strict:
- conf.env.append_value(f, ['-Wunused-parameter'])
+ conf.env.append_value(f, ['-Wunused-parameter', '-Wno-pedantic'])
autowaf.set_c_lang(conf, 'c99')
@@ -65,6 +65,7 @@ def configure(conf):
conf.define('PUGL_HAVE_GL', 1)
conf.check(features='c cshlib', lib='m', uselib_store='M', mandatory=False)
+ conf.check(features='c cshlib', lib='dl', uselib_store='DL', mandatory=False)
if not Options.options.no_cairo:
autowaf.check_pkg(conf, 'cairo',
@@ -232,7 +233,7 @@ def build(bld):
uselib=['CAIRO'],
source=['pugl/detail/x11_cairo.c'])
- def build_test(prog, platform, backend, **kwargs):
+ def build_test(prog, source, platform, backend, **kwargs):
use = ['pugl_%s_static' % platform,
'pugl_%s_%s_static' % (platform, backend)]
@@ -253,7 +254,7 @@ def build(bld):
deps.get(backend_lib, {}).get(k, []))})
bld(features = 'c cprogram',
- source = 'test/%s.c' % prog,
+ source = source,
target = target,
use = use,
install_path = '',
@@ -261,23 +262,27 @@ def build(bld):
if bld.env.BUILD_TESTS:
if bld.is_defined('HAVE_GL'):
- build_test('pugl_test', platform, 'gl', uselib=['M'])
+ build_test('pugl_test', ['test/pugl_test.c'],
+ platform, 'gl', uselib=['M'])
+ build_test('pugl_gl3_test',
+ ['test/pugl_gl3_test.c', 'test/glad/glad.c'],
+ platform, 'gl', uselib=['M', 'DL'])
if bld.is_defined('HAVE_CAIRO'):
- build_test('pugl_cairo_test', platform, 'cairo',
+ build_test('pugl_cairo_test', ['test/pugl_cairo_test.c'],
+ platform, 'cairo',
uselib=['M', 'CAIRO'])
if bld.env.DOCS:
bld(features = 'subst',
- source = 'Doxyfile.in',
- target = 'Doxyfile',
+ source = 'doc/reference.doxygen.in',
+ target = 'doc/reference.doxygen',
install_path = '',
- name = 'Doxyfile',
PUGL_VERSION = PUGL_VERSION,
PUGL_SRCDIR = os.path.abspath(bld.path.srcpath()))
bld(features = 'doxygen',
- doxyfile = 'Doxyfile')
+ doxyfile = 'doc/reference.doxygen')
def test(tst):